Sometimes, mostly in classes, I need to do a single line function.
For instance:
class Blah {
getVisibilityAnimValue() { return this.state.isVisible ? 100 : 0 }
}
In ES6 is there is any friendly way? I tried to omit the surrounding curlies and omitting the return but it's not working.
In ES6 is there is any friendly way?
No, there is not. As I think you already know, in order to use this to refer to the calling instance, you cannot use an arrow function (which uses the lexical this rather than a this based on how it was called). So, you have to use a conventional ES6 method definition. As such, you need the braces {} and you need the return.
The ES6 class syntax at least saves you the ES5 scheme of:
Blah.prototype.getVisibilityAnimValue = function() {...}
I tried to omit the surrounding curlies and omitting the return but it's not working.
Yep, those are still required.
If you had a lot of methods that worked just like this and used the identical logic, you could factor the logic into a shared function.
// define this once and then use it many places
function zVal(val) {
return val ? 0 : 100;
}
getVisibilityAnimValue() { return zVal(this.state.isVisible) }
But, for something this simple, it's arguable whether this is "better" since it now involves an extra function call and makes it a little harder to see (in a glance) what it does.
No. That is one of the exact reasons why arrow functions were created.
Related
Very often I come across code that looks something like this:
ngOnDestroy() {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
My question is if this is, while harmless in this example, a bad practice since the implication here is that there is a return value which is equal to whatever unsubscribe() method returns.
The code above does not have any need to return anything out of the arrow function, yet there is an implicit return there, i.e., the body is translated into return subscription.unsubscribe().
Would it be a better practice to code that function as follows? (note the extra curly braces):
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
subscription.unsubscribe();
});
}
Arrow function reduces code that you write so implicit return helps saving some key strokes :) However, in your 2nd example, even there is a return that is undefined. So it is not bad practice, it is cleaner and shorter.
It is a matter of style, but I would call unintended implicit return a bad one. It takes a bit less to type but gives wrong impression about API in use if a developer who reads the code isn't familiar with it. This is less of a problem for well-known API like forEach. Still, if a function returns a value but it's ignored, this may cause confusion.
Implicit return won't cause runtime issues if returned value is undefined, but in case it's defined, a value may affect the code where a function is being called in such way.
An example is a pitfall I accidentally fell once with AngularJS testing. Testing modules accept module configuration functions with same signatures as production modules (a function annotated for dependency injection that returns no value), but the value is just ignored in production module:
// ok
app.config((foo) => foo.barThatReturnsAValue());
While in tests it results in obscure error:
// Error: [ng:areq] Argument 'fn' is not a function, got Object
angular.mock.module((foo) => foo.barThatReturnsAValue())
The problem that is specific to TypeScript is that such problems usually aren't detected by type checks:
let foo = () => 1;
let bar = (foo: () => void) => {};
bar(foo); // ok
For cleaner code and increased readability you may also use the void keyword.
For example: (Note the void keyword after the =>)
ngOnDestroy() {
this.subscriptions.forEach(subscription => void subscription.unsubscribe());
}
No implicit return here :)
Both of your examples produces return results. If you don't really need any return value. You better use for loops
for(var i=0; i<this.subscriptions.length; i++)
{
this.subscription[i].unsubscribe();
}
Also for loops are much more efficient than forEach here
In theory, it would be a better practice to follow the second example for functions with return values.
In practice, however, it often does not matter if a callback function has a return value, so the cleaner syntax of the first example is worth the ambiguity.
edit: as Randy points out in the comments, if the function returns undefined, there is no difference between the two approaches. I amended my answer to take this into account.
Is there a simple way to prevent $bind generation when passing around class member functions?
I have an object that takes in a function which will be called in an arbitrary interval. The object always binds itself as the 'this' binding before calling the function (this is done in the native side), therefore the call to $bind itself is unnecessary. However, I can't seem to find a simple way to prevent $bind from being emitted any time I grab a member function by value.
The only way I've found is to use __js__ with a string literal of the member function name, which I would rather avoid... Is there a typed way to do so? Or something a bit nicer? A way to still use haxe syntax w/ identifiers instead of a string literal?
Example:
private function onSpawn():Void
{
this.setAct( act ); // Will generate JS: this.setAct($bind(this,this.act));
// Id like to simply have it generate: this.setAct( this.act );
// Mitigated like this:
this.setAct( untyped __js__("this.act") );
}
private function act( dt:Float ):Void
{
...
}
Thank you.
You use macro to mask out the untyped expression, but this is quite dangerous.
Any reference to "this" will fail.
http://try-haxe.mrcdk.com/#70ee4
Btw, I think the compiler may be optimized to not generate $bind if the function code doesn't involve "this". You may want to raise an issue in the github repo about that.
Eclipse has an option to warn on assignment to a method's parameter (inside the method), as in:
public void doFoo(int a){
if (a<0){
a=0; // this will generate a warning
}
// do stuff
}
Normally I try to activate (and heed) almost all available compiler warnings, but in this case I'm not really sure whether it's worth it.
I see legitimate cases for changing a parameter in a method (e.g.: Allowing a parameter to be "unset" (e.g. null) and automatically substituting a default value), but few situations where it would cause problems, except that it might be a bit confusing to reassign a parameter in the middle of the method.
Do you use such warnings? Why / why not?
Note:
Avoiding this warning is of course equivalent to making the method parameter final (only then it's a compiler error :-)). So this question Why should I use the keyword "final" on a method parameter in Java? might be related.
The confusing-part is the reason for the warning. If you reassign a parameter a new value in the method (probably conditional), then it is not clear, what a is. That's why it is seen as good style, to leave method-params unchanged.
For me, as long as you do it early and clearly, it's fine. As you say, doing it buried deep in four conditionals half-way into a 30-line function is less than ideal.
You also obviously have to be careful when doing this with object references, since calling methods on the object you were given may change its state and communicate information back to the caller, but of course if you've subbed in your own placeholder, that information is not communicated.
The flip side is that declaring a new variable and assigning the argument (or a default if argument needs defaulting) to it may well be clearer, and will almost certainly not be less efficient -- any decent compiler (whether the primary compiler or a JIT) will optimize it out when feasible.
Assigning a method parameter is not something most people expect to happen in most methods. Since we read the code with the assumption that parameter values are fixed, an assignment is usually considered poor practice, if only by convention and the principle of least astonishment.
There are always alternatives to assigning method parameters: usually a local temporary copy is just fine. But generally, if you find you need to control the logic of your function through parameter reassignment, it could benefit from refactoring into smaller methods.
Reassigning to the method parameter variable is usually a mistake if the parameter is a reference type.
Consider the following code:
MyObject myObject = new myObject();
myObject.Foo = "foo";
doFoo(myObject);
// what's the value of myObject.Foo here?
public void doFoo(MyObject myFoo){
myFoo = new MyObject("Bar");
}
Many people will expect that at after the call to doFoo, myObject.Foo will equal "Bar". Of course, it won't - because Java is not pass by reference, but pass by reference value - that is to say, a copy of the reference is passed to the method. Reassigning to that copy only has an effect in the local scope, and not at the callsite. This is one of the most commonly misunderstood concepts.
Different compiler warnings can be appropriate for different situations. Sure, some are applicable to most or all situations, but this does not seem to be one of them.
I would think of this particular warning as the compiler giving you the option to be warned about a method parameter being reassigned when you need it, rather than a rule that method parameters should not be reassigned. Your example constitutes a perfectly valid case for it.
I sometimes use it in situations like these:
void countdown(int n)
{
for (; n > 0; n--) {
// do something
}
}
to avoid introducing a variable i in the for loop. Typically I only use these kind of 'tricks' in very short functions.
Personally I very much dislike 'correcting' parameters inside a function this way. I prefer to catch these by asserts and make sure that the contract is right.
I usually don't need to assign new values to method parameters.
As to best-practices - the warning also avoids confusion when facing code like:
public void foo() {
int a = 1;
bar(a);
System.out.println(a);
}
public void bar(int a) {
a++;
}
You shoud write code with no side effect : every method shoud be a function that doesn't change . Otherwise it's a command and it can be dangerous.
See definitions for command and function on the DDD website :
Function :
An operation that computes and returns a result without observable side effects.
Command : An operation that effects some change to the system (for
example, setting a variable). An
operation that intentionally creates a
side effect.
This is related to, but in my mind not a duplicate of, Passing named arguments to a Javascript function [duplicate] and Named parameters in javascript.
Various answers and comments on those questions propose approaches to deal with the lack of JavaScript language support for named arguments.
The original poster's concern was this:
Calling a Javascript function with something like
someFunction(1, true, 'foo');
is not very clear without familiarity with the function.
Let's say someFunction is declared elsewhere in the code as:
function someFunction(numberOfClowns,wearingHat,screamingAtTopOfLungs) {
console.log(arguments)
}
Is there any particular reason why you couldn't call the function like this?
someFunction(numberOfClowns=1, wearingHat=true,screamingAtTopOfLungs='foo')
From my preliminary testing, this seems to not result in any errors, and certainly addresses any issues of clarity.
I guess you would need to var all of the variables beforehand, and be aware that variable assignment is occurring, so not be too surprised that numberOfClowns is now equal to 1. Anything else that I'm not considering?
Since you're just using the assignments as labels anyway, why not simply use comments?
someFunction(/*numberOfClowns=*/1, /*wearingHat=*/true, /*screamingAtTopOfLungs=*/'foo')
I've seen this done in C code (particularly for functions with 5 or more arguments), and it would avoid the nasty side-effects you mention.
Since there aren't actually any checks being done with the var-assignment version, this seems to have all the same benefits without the downsides.
I guess you would need to var all of the variables beforehand, and be aware that variable assignment is occurring
This is a major problem in my eyes. It makes this a whole more complicated than any of the other approaches, and it's not a local solution - you're polluting your scope.
Anything else that I'm not considering?
The main argument of named parameters/named arguments is that you can order and omit them however you want, and the right values will still end up in the right variables. Your approach does not provide this. Better just use objects as everyone does.
I'd wager there will be more problems than without the assignments.
As you say, assignments return the assigned value, so if the variables are properly declared, there is no problem. To avoid conflicts with other code in the same function, I suggest wrapping the call inside a block, and declaring the parameters with let.
function someFunction(numberOfClowns, wearingHat, screamingAtTopOfLungs) {
console.log(numberOfClowns, wearingHat, screamingAtTopOfLungs);
}
{
let numberOfClowns, wearingHat, screamingAtTopOfLungs;
someFunction(numberOfClowns=1, wearingHat=true, screamingAtTopOfLungs='foo');
}
You may also be interested in destructuring objects:
function someFunction({numberOfClowns, wearingHat, screamingAtTopOfLungs}) {
console.log(numberOfClowns, wearingHat, screamingAtTopOfLungs);
}
someFunction({numberOfClowns: 1, wearingHat: true, screamingAtTopOfLungs: 'foo'});
From Eloquent Javascript by Marijn Haverbeke
Different JavaScript platforms in different browsers have
traditionally done different things in that situation, and the latest
standard actually forbids it.
but why is it bad?
function example () {
function a () {} // Okay
if ( something ) {
function b () {} // Danger !
}
}
It's considered "bad" because its behavior is inconsistent and sometimes doesn't do what most people would expect. Consider the following snippet:
if (true) {
function f() { return "t"; }
} else {
function f() { return "f"; }
}
What would calling f() return? On IE and Firefox, it will return "t", but on Chrome and Safari, it will return "f". Why? A combination of hoisting and JavaScript's scoping rules. For information on how that works, see this question on JavaScript scoping and hoisting.
Effectively, this means that, on some browsers, the branch is completely ignored when it comes to function definitions using the function name() { ... } form. If you really need to do something like this (and you probably don't, since it would be very poor style, anyway), use the name = function () { ... } form instead, since that will not be hoisted, so the behavior is well-defined and will not be inconsistent across platforms.
This is standardized in ES6 and is valid to nest function declaration inside blocks. Here is the spec Block-Level-Function-Declarations
You can try in latest browsers with strict-mode turned on.
And for reasons why that behavior is present in old environments look here:
Functions
The short answer is already given to you, namely: such practice negatively affects the portability/compatibility of the solution between various browsers. What is even worse: it leads to the added ambiguity regarding the local variables, namely: which variables will be "visible" to which nested functions. Even though it could be considered allowed technique, but it doesn't mean that such technique is a good practice. "Code for the clarity" is the utterly important programming paradigm, so always try avoiding the practices which add to the ambiguity. Best regards,