In Ember, defining a property as a computed alias to another property (or another object's property) using Ember.computed.alias('otherProperty') seems to have basically the same result as defining it as a binding to that property using propertyNameBinding: 'otherProperty'.
I've looked at the source and the documentation but I can't find any reason why one would be preferred over the other. Obviously templates use bindings, which is fine, but for properties in e.g. controllers, or for referencing a controller's property on a view, is there a difference?
An alias can be overwritten on extend(), completely eliminating the relationship with the other key.
A brief example: I have a class of time-related functions and classes, and the classes have both a unit property (for Day, Minute, etc) and a precision property. Normally these are functionally identical. In one or two classes they diverge. Ember.computed.alias allows precision to alias to unit for most cases, but to be overridden with its own value as needed.
Note that create() will use the alias setter, instead of overriding.
Also, setting an alias with a null object in its path can blow up, while a binding will simply not sync if the path doesn't lead anywhere.
Please see morgoth's comment below per soft-deprecation of *Binding syntax
Related
I want to use derived attributes and references in an ecore model, but so far I have not found any documentation on how to set the code for the methods which compute the values of derived attributes/references.
As far as I understand it, the basic workflow is to mark an attribute/reference as derived, generate model code, and then manually add the implementation. However, I work with models dynamically generated through the Ecore API. Is there a way to take a String and specify this String as the implementation for the computation of the derived feature, without manually editing generated files?
EDIT>
To clarify: I'm looking for a way to directly change the generated Java files, by specifying method bodys (as strings) for the getters of derived EStructuralFeatures.
EMF provides a way of dealing with dedicated implementation for EOperation and derived EAttribute using "invocation delegate". This functionality allows you to put some implementation directly in your ecore metamodel in a string format (as soon as the used language can be "handled" by EMF, i.e, an invocation delegate exists).
As far as I know, OCL is well supported: https://wiki.eclipse.org/OCL/OCLinEcore#Invocation_Delegate
The registration of the invocation delegate is performed either by plugin registration or by hand (for standalone usage), and the mechanism works with the EMF reflection layer (dynamic EMF): https://wiki.eclipse.org/EMF/New_and_Noteworthy/Helios#Registering_an_Invocation_Delegate
(Please note that I never experienced this mechanism. I know it exists, but I never played with it.)
EDIT>
It seems that the question was not related to dynamic code execution for derived attribute, but to code injection (I misunderstood the "Is there a way to take a String and specify this String as the implementation for the computation of the derived feature?").
EMF provides a way of injecting code placed on the ecore metamodel directly into the generated code.
Here is the way for EAttribute with derived property. The EAttribute should have the following properties set to true: {derived volatile} (you can also add transient). If you only want a getter and no setter for your EAttribute, you can also set the property changeable to false.
Once your EAttribute is well "configured", you have to add a new EAnnotation with the source set to http://www.eclipse.org/emf/2002/GenModel and an entry with the key set to get and value set to your code that will be injected (see image below).
And voilĂ , your code will be generated with the value value injected in your getter.
You can add the same process for EOperation using body instead of get.
I'm writing a program that requires the user to be very flexible in manipulating data on a given object. I figured I would use a property browser of some kind; Qtilities' ObjectDynamicPropertyBrowser caught my eye.
However, I need to be able to add my own data types. The documentation is not clear on how to do so.
How can I allow my own data types to be represented in Qtilities' property browser widgets?
Also, more about my needs:
The data types are not part of Qt, nor are they even Q_OBJECTs.
Qt-specific modifications to the relevant classes are not an option.
Declaring the relevant classes via Q_DECLARE_METATYPE is okay.
In particular, I need to represent vector and matrix types (and possibly more later).
The browser you refer to depends on the QObject property system. So, unless your classes are QObjects, it won't work - but don't despair, Qt 5.5 to the rescue (read on). The browser seems to use a QTreeView and provides an adapter model that exposes the QObject property system. So, it leverages Qt's type and delegate system.
In Qt 5.5, there is a general purpose property system, known as gadgets, that can be used on any class, as long as there is a QMetaObject describing that class. By adding the Q_GADGET macro to a class deriving from the subject class, and describing the properties using Q_PROPERTY macro, you can leverage moc and the gadget system to access your unmodified types' properties.
The only reason you'd do that is to require minimal changes to the ObjectPropertyBrowser system. You don't want the ObjectDynamicPropertyBrowser, since it works on dynamic properties, and your objects don't have any. They have static properties, given through Q_PROPERTY macros and code generated by moc.
So, you'll proceed as you would for implementing your own type support for QVariant and views in general. You also need Qt 5.5, since you need gadget support for it to work. A solution for Qt 5.4 and below requires a different approach and might be less cumbersome to implement in another way.
See this answer for a reference on using gadget property system for object serialization, it's fundamentally what the property browser would do, sans the serialization proper of course.
There are three steps. First, you need to address simple custom types that don't have a structure, but represent a single value (such as a date, or time, or geographic position, etc.), or a collection of simple values (such as a matrix).
Ensure that QVariant can carry the simple types. Add the Q_DECLARE_METATYPE macro right after the type's definition in an interface (header file).
Implement delegates for the types. For types with table structure, such as a matrix, you can leverage QTableView and provide an adaptor model that exposes the type's contents as a table model.
Secondly, you get to your complex types that have internal structure:
Create a wrapper class that derives from the complex type, declares all properties using Q_PROPERTY, and has the Q_GADGET macro (not Q_OBJECT since they are not QObjects). Such class should not have any members of its own. Its only methods should be optional property accessors. The Q_GADGET macro adds the static (class) member staticMetaObject.
The underlying type can be static_cast to the wrapper class if needed, but that's normally not necessary.
At this point, any class that you wrote a wrapper for is accessible to the QMetaProperty system directly, without casting! You'd use the wrapper's staticMetaObject for its static metaobject, but the QMetaProperty readOnGadget and writeOnGadget will take the pointers to the base class directly.
Thirdly, since ObjectPropertyBrowser most likely doesn't implement the support for gadgets in Qt 5.5, as that's quite new, you'll have to modify it to provide such support. The changes will be minimal and have to do with using QMetaProperty::readOnGadget and QMetaProperty::writeOnGadget instead of QMetaProperty::read and QMetaProperty::write. See the serialization answer for comparison between the two.
I am trying to use synthesised accessors on a component on Lucee (although this issue seems to be the same on ColdFusion too).
Repro code:
// Person.cfc
component accessors=true {
property firstName;
property lastName;
function init(firstName, lastName){
variables.firstName = arguments.firstName;
variables.lastName = arguments.lastName;
}
}
And the calling code:
// person.cfm
person = new Person("Abigail", "Bowen");
writeDump(person);
Notice how I am not using the synthesised accessors here, I am purely setting the argument values into same-named variables-scoped variables.
However when I run this code, I see this:
Note how the properties have been populated. There's no problem with this, but I'm clearly not understanding how the accessors flag is supposed to work. I thought it was merely intended to synthesise some accessor methods for me (which it has), but that's all.
Also note that if I modify the CFC definition to not set accessors to true, then the dump shows this:
So no synthesised accessors (as expected), but also now the properties aren't even being displayed (with the variables-scoped values or not).
I don't really understand this conflation of "properties" and the accessors setting? Surely the accessors setting should only impact whether those accessor methods get created?
If I was only seeing this on one of the platforms, I'd probably put it down to a vagary of how writeDump() interprets the property definitions. But the behaviour is the same on ColdFusion 11, so it really does seem like there's some difference in behaviour I'm not quite getting.
Can anyone explain this? Are there any docs which explain it? If not... um... why not?
My underlying concern here is that the property values are not being stored "properly" and might cause me problems once I implement more of the code.
UPDATE:
At least on ColdFusion, it seems to be just a change in writeDump()'s behaviour, because if there are getters for the properties (whether or not the accessors flag is set) then the property values start showing up in the dump. This is not the case on Lucee though, so there's still a question mark there.
For the sake of full disclosure, this question is a summary of a question I also asked on my blog ("CFML: trying to understand accessors"). The duplication is intentional as my blog gets a different audience from that of this site.
Without accessors=true, the property declarations are just metadata.
With accessors=true, the property declarations trigger the generation of getters / setters and thus a property is both a variables scope item and a pair of methods.
In your constructor, you assign to the variables scope items -- which would be the same as using the generated setters -- and when CFML dumps the component, it sees the property metadata and the generated getters and so it displays the values those properties have (since it can easily and safely call the generated getters).
This came up with ACF9. Until then the definition in the property docs was right: cfproperty declarations are just metadata. (see dump(getMetaData()).
In ACF9 this was not fully correct anymore for 3 reasons:
With accessors=true a getter and setter is generated for each property and those accessors read from and write to the variables scope. Cfproperty is not just metadata anymore, but has a direct effect on the behaviour of the instance. I like to think about it as the CF version of real OO properties (introduced by accident).
The cfdump implementation changes its behaviour based on the property declarations. If property name; is defined and method getName() exists (generated or implemented) it is added to the property section of the dump.
The property attributes control the ORM.
Since I got to know those features, I design all my (public) CFCs to look right when dumped, eg. I only use the property declaration (+ getters) when I want to have it visible. In addition, you can implement methods that are only called by the dumps and cost nothing on instantiation:
struct function getDebug(){
var x = doSomethingExpensive();
return { "Foo":f, "Bar":b, "Baz":x };
}
//or for a user iterator
string function getName(){
return qUsers.name[index];
}
Some caveats I know:
ACF always calls the getters from the dumps, while in Railo/Lucee the value from the variables scope is shown. Thus, the above examples (getDebug()and getName()) don't work on Railo/Lucee.
If the getter is not public or results in an error, the dump shows an empty string for the property (not sure here, maybe the property is missing instead).
Property declarations in extended CFCs are ignored. This gave me some headache in ORM entities that use inheritance, because you are not allowed to declare a property twice. Thus, you have no possibility to show a property that is defined in a base CFCs.
Railo/Lucee seems to ignore the property types. All accessor accept and return only strings (see getMetaData()).
Minor: In ACF when you activate the accessors, but deactivate getter and setter for a property: property name="user" getter="false" setter="false"; it is still visible in the dump - it should be hidden.
It is well know how to build the adapter when the adaptee's methods look same except for the name.
For example,
http://sourcemaking.com/design_patterns/adapter/cpp/2
where none of "doThis", "doThat", and "doOther" has inputs. However, what if different methods have different number of input parameters?
Thanks
The example given in linked document describes a use of the adapter pattern in a situation where the change is purely syntactic. The situation implied by your question contains a semantic change, ie the adaptee method does not provide the exact same service than what the adapter interface "promises" to deliver formally. This means that the adaptee's must be somehow wrapped with more than a simple name change: some work must be done around it to build the missing parameters or transform the existing parameters into those required by the adaptee.
If each new adaptee has different requirements, then each adapter must contain the ad-hoc adapting code. There's not much one can do to factor out a common pattern out of this situation. The only easy case is the trivial one, when all the needed parameters are independent of the passed ones, and can be computed once for all before constructing the adapter, hence allowing an adapter as a simple std::bind equivalent.
Something I find very counter-intuitive about Ember is you can overwrite a computed property setter functions ( http://emberjs.com/#toc_computed-properties-setters ) with the arguments to create(). See http://jsfiddle.net/zJQJw/2/
I found the best workaround for this is to call create().setProperties(properties) instead of create(properties), but this seems like an unnecessary gotcha to me. I realize it might break some apps at this point, but would you consider making create() behave more like setProperties()?
My motivation for asking for this is that init() will be called before setProperties() when using the create().setProperties(properties) pattern. This hasn't been a big problem yet, but I can see this being undesirable in some situations. This is a completely contrived example, but maybe you can see what I am getting at? http://jsfiddle.net/QJ8vX/2/
The only reason I can see for maintaining the current behavior is to do instance-specific overrides of setter methods. But in those cases you could just as easily do MyClass.extend({ overridenMethod: ... }).create(properties)
Would a change like this be considered for Ember 1.0? Or do I just have the wrong idea about how Ember's object model should work?
The main reason why we've pushed back on this change is that it makes it impossible to override properties that are defined on base classes as computed properties. For example, in Ember.View, the template property is a computed property:
template: Ember.computed(function(key, value) {
if (value !== undefined) { return value; }
var templateName = get(this, 'templateName'),
template = this.templateForName(templateName, 'template');
return template || get(this, 'defaultTemplate');
}).property('templateName').cacheable(),
When creating a subclass of Ember.View, you may want to override this definition with an explicit template function:
Ember.View.create({ template: Ember.Handlebars.compile('...') });
If the computed property doesn't handle the setter case, this attempt to override the computed property would be a silent failure.
If we made this change, it also introduces other questions about whether observers should trigger for properties passed into the create method. Both are possible to implement, and there are strong arguments for both approaches.
In the run-up to 1.0, it seems reasonable to consider an approach that would:
change create to use setProperties semantics
add a new API (override or createWithOverride) that would retain the existing semantics, in case you explicitly wanted to override existing computed properties
suppress observers for properties set due to create (or decide not to)
find a way to detect and warn about attempts to use the create API with computed properties that do not implement setters.
I would need to discuss it more, and consider the implications to existing apps, but it is definitely something worth considering, as it is definitely a pretty big gotcha for new developers. The fact that we needed to change the behavior for ember-data is a pretty good clue that something isn't quite right.
It's may be a dirty hack, but it's works for me.
Em.Object.reopenClass({
create: function(config) {
return this._super().setProperties(config);
}
});