What are the non-expressions in CoffeeScript? - coffeescript

I am watching this great video by Jeremy on CoffeeScript. He explains that one of the ideals of CoffeeScript is to have "everything be an expression".
How close to this ideal has CoffeeScript got? What are the CoffeeScript non-expressions?

There are a few things that are not converted into expressions in coffeescript, as explained in the documentation:
There are a handful of statements in JavaScript that can't be meaningfully converted into expressions, namely break, continue, and return. If you make use of them within a block of code, CoffeeScript won't try to perform the conversion.
Everything else is wrapped in function closures and handled by coffeescript, which means you can do cool stuff like
alert(
try
nonexistent / undefined
catch error
"And the error is ... #{error}"
)

Related

Does order matter in Dart?

All apologies for the noob question. Does the order variables etc are in affect how they are executed? Does it read left to right and down like a human and execute in order, or does it look at everything at once and execute based on priority, or some combination of both?
Look at operator table in official language tour for dart to know which operator precedes other one.
https://dart.dev/guides/language/language-tour#operators
There are some operators where RHS is executed first (like assignment operator aka '=') and there are others where LHS is executed first (like '+', '&&' etc). If you are not sure which operator might execute first, try using brackets or use intermediate variables. It gives better readability to other developers without confusion.
Also,
Dart code is executed in procedural manner (line 1 would execute before line 2 unless async call is made). Learn more about it with EventLoop. More info at https://dart.dev/guides/libraries/library-tour#dartasync---asynchronous-programming

Macros do not allow definition of lexical variables

This code that uses (experimental) macros:
use experimental :macros;
macro new-var() {
quasi {
my $a = 42
}
};
new-var;
say $a
Fails with Variable '$a' is not declared, although the macro passes through without an error. If that's a correct macro declaration, what does it do? If it's not, is there a way to define new variables from within a macro?
The answer from moritz is correct about the state of macros, though from what I know of the work being done in 007, I don't think the program as written would be correct even with a working implementation of Perl 6 macros.
Perl 6 macros will not be textual in nature (C macros are an example of textual ones). A quasi is a quote construct, much like we have quotes for strings and regexes, except that it quotes Perl 6 code, representing it as something AST-ish. (I once would have said that it produces AST, but it's been realized that if an infix were to be interpolated inside of a quasi, then it comes with a precedence and associativity, and we we can't actually form the correct tree for the expression until after interpolation.)
There's a macro concept of "hygiene", whereby symbols declared in the macro body should not, by default, leak out to the place that the macro is applied, since they may well just be implementation details. One would have to explicitly ask to put a symbol into the compiling context where the macro is applied. So I expect the program would have to look like this:
macro new-var() {
quasi {
my COMPILING::<$a> = 42
}
};
new-var;
say $a
Note that this won't work today in Rakudo, although you might find something like it can be made to work in 007.
This might not be the answer you are looking for, but macros in Rakudo are currently really broken. At this point in time I can't even remember if it's supposed to work, or if it's a bug in Rakudo -- it's mostly not worth it figuring it out, because most macro things barely work at all.
This is why Carl Mäsak created 007 to experiment with Macro design outside of Rakudo core, with the goal of eventually bringing the lessons learned back to Rakudo and the Perl 6 language design.

Coffeescript whitespace, arguments and function scopes

I've been using CoffeeScript for a while. I find it a good language overall, certainly better than plain JS, but I find I'm still baffled by its indentation rules. Take this example:
Bacon.mergeAll(
#searchButton.asEventStream('click')
#searchInput.asEventStream('keyup')
.filter (e) => e.keyCode is 13
)
.map =>
#searchInput.val()
.flatMapLatest (query) =>
Bacon.fromPromise $.ajax
url: #searchURL + encodeURI query
dataType: 'jsonp'
This does what it should (the code is based on this tutorial, btw) but it took me a lot of trial and error to get it right.
Why do mergeAll and asEventStream require parentheses around their arguments? Why is indentation not enough to determine where their argument lists begin and end? OTOH, why is indentation enough for map and flatMapLatest? Why is the whitespace before a hanging method, such as .filter (its indentation level) not enough to determine what it binds to? It seems to be completely ignored.
Is there a definitive guide to this language's indentation rules? I never had a problem understanding Python syntax at a glance, even with very complex nesting, so it's not an issue with indentation-based syntax per se.
Indentation in CoffeeScript generally defines blocks, and argument lists aren't (necessarily) blocks. Similarly, a chained function call isn't a block; CoffeeScript simply sees a line starting with . and connects it to the previous line of similar or lower indentation.
Hence, the parentheses are needed for asEventStream, since CoffeeScript would otherwise see:
#searchInput.asEventStream 'keyup'.filter (e) => e.keyCode is 13
Which would call filter on the 'keyup' string, and it'd remain ambiguous whether the function is an argument to filter, or an argument to #searchInput.asEventStream('keyup'.filter)(). That last bit obviously doesn't make much sense, but CoffeeScript isn't a static analyzer, so it doesn't know that.
A function, meanwhile, is a block, hence the function argument to .map() works without parentheses, since it clearly delimited by its indentation. I.e. the line following the function has less indentation.
Personally, I'd probably write
Bacon.mergeAll(
#searchButton.asEventStream('click'), # explicit comma
#searchInput.asEventStream('keyup').filter (e) -> e.keyCode is 13 # no need for =>
)
.map(=> #searchInput.val()) # maybe not as pretty, but clearer
.flatMapLatest (query) =>
Bacon.fromPromise $.ajax
url: #searchURL + encodeURI query
dataType: 'jsonp'
In fact, I might break it up into separate expressions to make it clearer still. Insisting on the syntactic sugar while chaining stuff can indeed get confusing in CoffeeScript, but remember that you're not obliged to use it. Same as you're not obliged to always avoid parentheses; if they make things clearer, by all means use 'em!
If the code's easier to write, less ambiguous to read, and simpler to maintain without complex chaining/syntax (all of which seems true for this example), then I'd say just skip it.
In the end, there just are combinations of indentation syntax in CoffeeScript that can make either you or the compiler trip. Mostly, though, if you look at something, and find it straightforward, the compiler probably thinks so too. If you're in doubt, the compiler might be too, or it'll interpret it in unexpected ways. That's the best I can offer in terms of "definitive guide" (don't know of a written one).
Have you looked at the Javascript produced by this code? What happens when you omit ().
In Try Coffeescript I find that:
#searchButton.asEventStream 'click'
is ok. The second asEventStream compiles to:
this.searchInput.asEventStream('keyup').filter(function(e) {
but omitting the () changes it to:
this.searchInput.asEventStream('keyup'.filter(function(e) {
filter is now an attribute of 'keyup'. Putting a space to separate asEventStream and ('keyup') does the same thing.
#searchInput.asEventStream ('keyup')
As written .mergeAll() produces:
Bacon.mergeAll(...).map(...).flatMapLatest(...);
Omitting the ()
Bacon.mergeAll
#searchButton.asEventStream('click')
#searchInput.asEventStream('keyup')
gives an error because the compiler has no way of knowing that mergeAll is a function that takes arguments. It has no reason to expect an indented block.
Coming from Python, my inclination is to continue to use (),[],{} to mark structures like arguments, arrays and objects, unless the code is clearer without them. Often they help me read the code, even if the compiler does not need them. Coffeescript is also like Python in the use of indentation to denote code blocks (as opposed to the {} used in Javascript and other C styled languages).

Why do Perl control statements require braces?

This may look like the recent question that asked why Perl doesn't allow one-liners to be "unblocked," but I found the answers to that question unsatisfactory because they either referred to the syntax documentation that says that braces are required, which I think is just begging the question, or ignored the question and simply gave braceless alternatives.
Why does Perl require braces for control statements like if and for? Put another way, why does Perl require blocks rather than statements, like some other popular languages allow?
One reason could be that some styles dictate that you should always use braces with control structures, even for one liners, in order to avoid breaking them later, e.g.:
if (condition)
myObject.doSomething();
else
myObject.doSomethingElse();
Then someone adds something more to the first part:
if (condition)
myObject.doSomething();
myObject.doSomethingMore(); // Syntax error next line
else
myObject.doSomethingElse();
Or worse:
if (condition)
myObject.doSomething();
else
myObject.doSomethingElse();
myObject.doSomethingMore(); // Compiles, but not what you wanted.
In Perl, these kinds of mistakes are not possible, because not using braces with control structures is always a syntax error. In effect, a style decision has been enforced at the language syntax level.
Whether that is any part of the real reason, only Larry's moustache knows.
One reason could be that some constructs would be ambiguous without braces :
foreach (#l) do_something unless $condition;
Does unless $condition apply to the whole thing or just the do_something statement?
Of course this could have been worked out with priority rules or something,
but it would have been yet another way to create confusing Perl code :-)
One problem with braceless if-else clauses is they can lead to syntactic ambiguity:
if (foo)
if (bar)
mumble;
else
tumble;
Given the above, under what condition is tumble executed? It could be interpreted as happening when !foo or foo && !bar. Adding braces clears up the ambiguity without dirtying the source too much. You could then go on to say that it's always a good idea to have the braces, so let's make the language require it and solve the endless C bickering over whether they should be used or not. Or, of course, you could address the problem by getting rid of the braces completely and using the indentation to indicate nesting. Both are ways of making clear, unambiguous code a natural thing rather than requiring special effort.
In Programming Perl (which Larry Wall co-authored), 3rd Edition, page 113, compound statements are defined in terms of expressions and blocks, not statements, and blocks have braces.
Note that unlike in C and Java,
[compound statements] are defined in
terms of BLOCKS, not statements.
This means that the braces are
requried--no dangling statements
allowed.
I don't know if that answers your question but it seems like in this case he chose to favor a simple language structure instead of making exceptions.
Perhaps not directly relevant to your question about (presumably) Perl 5 and earlier, but…
In Perl 6, control structures do not require parentheses:
if $x { say '$x is true' }
for <foo bar baz> -> $s { say "[$s]" }
This would be horrendously ambiguous if the braces were also optional.
Isn't it that Perl allows you to skip the braces, but then you have to write statement before condition? i.e.
#!/usr/bin/perl
my $a = 1;
if ($a == 1) {
print "one\n";
}
# is equivalent to:
print "one\n" if ($a == 1);
"Okay, so normally, you need braces around blocks, but not if the block is only one statement long, except, of course, if your statement would be ambiguous in a way that would be ruled by precedence rules not like you want if you omitted the braces -- in this case, you could also imagine the use of parentheses, but that would be inconsistent, because it is a block after all -- this is of course dependent on the respective precedence of the involved operators. In any case, you don't need to put semicolons after closing braces -- it is even wrong if you end an if statement that is followed by an else statement -- except that you absolutely must put a semicolon at the end of a header file in C++ (or was it C?)."
Seriously, I am glad for every explicitness and uniformity in code.
Just guessing here, but "unblocked" loops/ifs/etc. tend to be places where subtle bugs are introduced during code maintenance, since a sloppy maintainer might try to add another line "inside the loop" without realizing that it's not really inside.
Of course, this is Perl we're talking about, so probably any argument that relies on maintainability is suspect... :)

Is it possible to define a macro that looks almost like a comment?

I try to make a useful macro for logging. But I find that NSLog and all other sort of macros that carry textual information with them simply distract a lot from the code.
Is there any way to "hack" Xcode in a way that it will interpret something like
/*** do this because of that ***/
as a macro call, which results in calling NSLog, for example? I want those logs to "feel" like comments. Anything else that looks like critical code is just distracting and reduces productivity at the end, and then there's no real benefit from logging what's going on.
Is it possible to define a macro that looks almost like a comment?
Why do you want to make your code less readable?
The answer is no, and that's a good thing.
Is there any way to "hack" Xcode in a way that it will interpret something like
/*** do this because of that ***/
as a macro call…
Probably, but that's useless. All that would do is make the syntax coloring incorrect (coloring this comment as if it were a function call). The compiler (either GCC or Clang) would still see this as the comment that it is.
Making the compiler think it's a function call or macro invocation is what would actually achieve log output at run time, but even if you could do that, it's still a bad idea because you would have a function call or macro invocation disguised as a comment.
If you want your program to log messages, write logging code:
NSLog(#"Do %# because of %#.", foo, bar);
This code is explicitly code that does something at runtime. No mystery. No surprises. That's why it's better.
You can enclose one or more lines of NSLog in curly braces and then use Xcode's folding option to hide them.
Example:
{
NSLog(#"<#label#>");
NSLog(#"<#label#>");
}
when folded look like:
{...}
The braces will also indent the statements when unfolded making them more visually distinct.
I think you should reconsider your use of log statements. If you have as many logs statements as lines of code something is wrong. You should be using the debugger to print most values and messages. If you have that many log statements you reach a point where mistakes in the log statements produce more bugs than the code. You also have a big problem cleaning up the code for release.
Not that I know of (though I may be wrong!)
I think that if you want it to look different, a macro is probably the best that you can hope for - at least it will be highlighted a different color :)