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);
}
});
Related
In Ember.js, there are a lot of functions that require you to call this._Super(...arguments) before calling them. A quick example from the documentation:
import Component from '#ember/component';
export default Component.extend({
didRender() {
this._super(...arguments);
console.log('I rendered!');
}
});
Are there ever cases in Ember where we do not need to call this._super()? The reason I ask is because often times, I will write some hooks for either my controllers or routes where I simply forget to call this._super(...arguments) and, as far as I can tell, everything works the same.
Should I always include a super() method before overwriting any member function in Ember?
Yes, you better include this._super, although it is not "a must" in most cases.
There is only one place I know where this is critical - init. Most probably constructor too, as mentioned above, but I never needed to overwrite a constructor. However, consider this:
As many people mentioned, something might be changed in future versions and including this._super may help to avoid bugs
If you use mixin from some ember addon, they might also overwrite ember methods or do it in future versions
Let's say you are extending component from your own mixin and right now your mixin does not overwrite didRender. But what if you will need to change that in future?
So, while in most cases including this._super is not critical, it is good to include it anyway. Except cases when you intended to completely overwrite default behavior.
Yes. In a long lost thread someone once told me that the behavior of the overridden method was not necessarily guaranteed by semver so I should always call super to avoid strangeness in the future if something was added to an upstream method that is currently doing nothing.
Yes you should always do so. If you don't, ember won't execute the code that handles behind the scenes stuff which will result in weird behaviour you might not be able to debug..
P.S : As an experiment just try overriding a setupController method in any route in your app without calling this._super(...arguments) and see what happens.
Ember's Em.ArrayProxy and Em.Array have many programatic methods available for notifying observers of changes to content. For example:
arrayContentDidChange
arrayContentWillChange
enumerableContentDidChange
enumerableContentWillChange
contentArrayWillChange
Em.ArrayProxy also has several methods for manipulating the ArrayProxy's content. For example:
this.pushObject('something random');
// Or
this.insertAt(2, 'something random');
When using the latter methods, does one have to use them in conjunction with the former methods? It seems silly that Ember's usually-automated property observers would require a manual kick here but I don't find the documentation very clear.
No, you don't have to use any methods in conjunction.
If you want to add items to your ArrayProxy, simply pushObject(). You would know this by just using the method and seeing that it just works.
From the docs:
This mixin implements Observer-friendly Array-like behavior. It is not a concrete implementation, but it can be used up by other classes that want to appear like arrays.
http://emberjs.com/api/classes/Ember.Array.html
Ember.Array is a type of class that in other programming languages (without mixins) receives the name of an interface.
An ArrayProxy wraps any other object that implements Ember.Array
http://emberjs.com/api/classes/Ember.ArrayProxy.html
Ember.ArrayProxy is exactly what the name says, a proxy, that wraps around any object that has implemented the Ember.Array interface.
The other methods, that you mention, might be implemented/overridden if you are making your own "subclass" of Ember.Array. Some must be implement to make your subclass ArrayProxy friendly. Or if you want to add custom behaviour, maybe write to a log whenever arrayContentDidChange, then you override that method and add whatever logic your app needs.
That is Object Oriented Programming and all those explanations are out of scope for the documentation of any framework.
Are you asking whether pushObject et cetera trigger those events?
From the documentation for insertAt:
This will use the primitive replace() method to insert an object at the specified index.
From the documentation for replace:
You should also call this.enumerableContentDidChange()
So, yes, a properly implemented ArrayProxy will trigger those events when you add or remove things.
I have several objects which are behaving very similarly. I would like to provide a base implementation for the controllers related to those objects, and then extend those controllers to slightly customize the behaviour. I am doing something like this:
App.BaseIndexController = Ember.ArrayController.extend({
...
});
And now I would use the base controller to define my real object controller:
App.AgentsIndexController = App.BaseIndexController.extend({
....
});
I have two questions:
Are there any general comments discouraging this kind of reuse?
Is the extend mechanism the right way to reuse a generic controller implementation, ensuring that no state data will "leak" between controllers extending the same base controller?
You can do it as you've suggested, but note that any properties defined in App.BaseIndexController will leak over if they've been initiated (check this out for a common mistake)
Mixins can also work well, since they're more reusable. Ember uses Mixins a lot internally so you can't go wrong with that approach.
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
Sometimes when fixing a defect in an existing code base I might (often out of laziness) decide to change a method from:
void
MyClass::foo(uint32_t aBar)
{
// Do something with aBar...
}
to:
void
MyClass::foo(uint32_t aBar, bool aSomeCondition)
{
if (aSomeCondition)
{
// Do something with aBar...
}
}
During a code review a colleague mentioned that a better approach would be to sub-class MyClass to provide this specialized functionality.
However, I would argue that as long as aSomeCondition doesn't violate the purpose or cohesion of MyClass it is an acceptable pattern to use. Only if the code became infiltrated with flags and if statements would inheritance be a better option, otherwise we would be potentially be entering architecture astronaut territory.
What's the tipping point here?
Note: I just saw this related answer which suggests that an enum may be a better
choice than a bool, but I think my question still applies in this case.
There is not only one solution for this kind of problem.
Boolean has a very low semantic. If you want to add in the future a new condition you will have to add a new parameter...
After four years of maintenance your method may have half a dozen of parameters, if these parameters are all boolean it is very nice trap for maintainers.
Enum is a good choice if cases are exclusive.
Enums can be easily migrated to a bit-mask or a context object.
Bit mask : C++ includes C language, you can use some plain old practices. Sometime a bit mask on an unsigned int is a good choice (but you loose type checking) and you can pass by mistake an incorrect mask. It is a convenient way to move smoothly from a boolean or an enum argument to this kind of pattern.
Bit mask can be migrated with some effort to a context-object. You may have to implement some kind of bitwise arithmetics such as operator | and operator & if you have to keep a buildtime compatibility.
Inheritence is sometime a good choice if the split of behavior is big and this behavior IS RELATED to the lifecycle of the instance. Note that you also have to use polymorphism and this is may slow down the method if this method is heavily used.
And finally inheritence induce change in all your factory code... And what will you do if you have several methods to change in an exclusive fashion ? You will clutter your code of specific classes...
In fact, I think that this generally not a very good idea.
Method split : Another solution is sometime to split the method in several private and provide two or more public methods.
Context object : C++ and C lack of named parameter can be bypassed by adding a context parameter. I use this pattern very often, especially when I have to pass many data across level of a complex framework.
class Context{
public:
// usually not a good idea to add public data member but to my opinion this is an exception
bool setup:1;
bool foo:1;
bool bar:1;
...
Context() : setup(0), foo(0), bar(0) ... {}
};
...
Context ctx;
ctx.setup = true; ...
MyObj.foo(ctx);
Note:
That this is also useful to minimize access (or use) of static data or query to singleton object, TLS ...
Context object can contain a lot more of caching data related to an algorithm.
...
I let your imagination run free...
Anti patterns
I add here several anti pattern (to prevent some change of signature):
*NEVER DO THIS *
*NEVER DO THIS * use a static int/bool for argument passing (some people that do that, and this is a nightmare to remove this kind of stuff). Break at least multithreading...
*NEVER DO THIS * add a data member to pass parameter to method.
Unfortunately, I don't think there is a clear answer to the problem (and it's one I encounter quite frequently in my own code). With the boolean:
foo( x, true );
the call is hard to understand .
With an enum:
foo( x, UseHigherAccuracy );
it is easy to understand but you tend to end up with code like this:
foo( x, something == someval ? UseHigherAccuracy : UseLowerAccuracy );
which is hardly an improvement. And with multiple functions:
if ( something == someval ) {
AccurateFoo( x );
}
else {
InaccurateFoo( x );
}
you end up with a lot more code. But I guess this is the easiest to read, and what I'd tend to use, but I still don't completely like it :-(
One thing I definitely would NOT do however, is subclass. Inheritance should be the last tool you ever reach for.
The primary question is if the flag affects the behaviour of the class, or of that one function. Function-local changes should be parameters, not subclasses. Run-time inheritance should be one of the last tools reached for.
The general guideline I use is: if aSomeCondition changes the nature of the function in a major way, then I consider subclassing.
Subclassing is a relatively large effort compared to adding a flag that has only a minor effect.
Some examples:
if it's a flag that changes the direction in which a sorted collection is returned to the caller, that's a minor change in nature (flag).
if it's a one-shot flag (something that affects the current call rather than a persistent change to the object), it should probably not be a subclass (since going down that track is likely to lead to a massive number of classes).
if it's a enumeration that changes the underlying data structure of your class from array to linked list or balanced tree, that's a complex change (subclass).
Of course, that last one may be better handled by totally hiding the underlying data structure but I'm assuming here that you want to be able to select one of many, for reasons such as performance.
IMHO, aSomeCondition flag changes or depends on the state of current instance, therefore, under certain conditions this class should change its state and handle mentioned operation differently. In this case, I can suggest the usage of State Pattern. Hope it helps.
I would just change code:
void MyClass::foo(uint32_t aBar, bool aSomeCondition)
{
if (aSomeCondition)
{
// Do something with aBar...
}
}
to:
void MyClass::foo(uint32_t aBar)
{
if (this->aSomeCondition)
{
// Do something with aBar...
}
}
I always omit bool as function parameter and prefer to put into struct, even if I would have to call
myClass->enableCondition();