How to split long conditional expressions in coffeescript? - coffeescript

Here is my conditional expression in coffeescript. How can I split it over multiple lines to make it more readable.
isWhat = (isAdd url) or (isUpdate url) or (isDelete url) or (isLockList url) or (isPasswordList url) or (isRemoteOpen url) or (isOpenRecord url)

In coffeescript you can split conditional expressions over multiple lines as long as you indent the continued expression one level so it knows to execute it as one expression.
It'll depend on your preference or style guide whether you put the or at the end of the line, or the start of the next line.
I would also suggest wrapping the function arguments in parenthesis, rather than the whole function. This makes it easier to read, yet still prevents coffeescript from executing the or before the function.
isWhat = isAdd(url) or
isUpdate(url) or
isDelete(url) or
isLockList(url) or
isPasswordList(url) or
isRemoteOpen(url) or
isOpenRecord(url)

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

Swift Command Line Tool - replacing regex in a long string is very slow

I'm writing a small command line tool in Xcode using swift. I have a string that's about 80 lines long and it contains something like this (possibly multiple times):
#if true
This should be here
#else
This should not be here
#endif
I want to replace all occurrences of this with This should be here, or whatever is written between #if true and #else.
(I'm doing the same for #if false)
I'm doing it like this:
let contents = try String(contentsOf: myFileURL)
contents = contents.replacingOccurrences(of: "#if true\n((.*|\n)*)#else\n(?:(.*|\n)*)#endif", with: "$1", options: .regularExpression)
This technically works, but only if contents is really small, otherwise it takes way too long (I quit the program after a minute).
Why is this so incredibly slow? Is the regex expression too complicated (regex101.com also can't do it on a large string)? I wouldn't know how to simplify it. Is there a better way to do what I'm trying to do?
Thank you for any help

Why do string macros in Julia use ...?

I was looking at the source for the r_str macro in Julia, which parses r"text" into Regex("text"). The second argument is flags..., which passes flags into the regex, like i for case insensitive, and so on.
I was playing with this myself and got:
julia> macro a_str(p, flags...)
print(flags)
p
end
julia> a"abc"iii
("iii",)"abc"
So it seems that the iii is all passed in as the first flag. In that case, why is there the ... on the flags. Is it possible to pass in more than one element of flags to the macro?
When this question was originally asked, a macro expander – i.e. the function defined with the macro keyword, which is called to transform the expressions passed to a macro into a single output expression – was not a generic function, but rather an anonymous function, which were a different kind of function in Julia 0.4 and earlier. At that point, the only way to write an anonymous function signature which could work for either one or two arguments was to use a trailing varargs argument, which is why this pattern was used to define string macros. In Julia 0.5 all functions have become generic functions, including anonymous functions and macro expanders. Thus, you can now write a macro a variety of ways, including the old way of using a varargs argument after the string argument:
# old style
macro rm_str(raw, rest...)
remove = isempty(rest) ? "aeiouy" : rest[1]
replace(raw, collect(remove), "")
end
# new style with two methods
macro rm_str(raw)
replace(raw, ['a','e','i','o','u','y'], "")
end
macro rm_str(raw, remove)
replace(raw, collect(remove), "")
end
# new style with default second argument
macro rm_str(raw, remove="aeiouy")
replace(raw, collect(remove), "")
end
These all result in the same non-standard string literal behavior:
julia> rm"foo bar baz"
"f br bz"
julia> rm"foo bar baz"abc
"foo r z"
The string literal produces the string with the flagged letters stripped from it, defaulting to stripping out all the ASCII vowels ("aeiouy"). The new approach of using a second argument with a default is the easiest and clearest in this case, as it will be in many cases, but now you can use whichever approach is best for the circumstances.
With an explicit call like
#a_str("abc", "iii", "jjj")
you can pass multiple flags. But I'm not aware of a way to make this work with a"abc"ijk syntax.
I don't believe it is possible, and the documentation doesn't provide an example where that would be used. In addition, the mostly-fully-compliant JuliaParser.jl doesn't support multiple flags either. Perhaps open an PR on Julia changing that?

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).

Which regexp is faster

I am using PCRE|^/foo/(.*?)(?::(?:bar)?)?$| or |^/foo/(.*?)(?::bar)?:?$| this will be a replace so we want to strip : and :bar from the end while doing the replacement. I know the two are not exactly the same but it does not matter much here.
I would use the first one as it only has to check for : once. The second one could match the first three characters of :bat before having to backtrack, then check for : again. Also, the second one could match :bar: whereas the first one can't. The actual speed difference would be tiny. The second way would be better written as /^\/foo\/(.*?)(?::bar|:)?$/
Try not to use regex metacharacters as delimiters!