Ask HN: Your favorite syntactic sugar from any language?
Most programming languages I've encountered, no matter how otherwise unappealing, have at least one syntactic feature that makes them really pleasurable for at least some type of task.
Some things I miss when I don't have them are:
* "=~" for regex matching (as in Perl and Ruby)
* "{foo:['bar','baz']}" for quick data structures (as in JavaScript)
* "for f in *; do echo $f; done" for looping over a 'glob' of files (as in Bash)
What's your favorite bit of sugar?
89 comments
[ 4.1 ms ] story [ 179 ms ] thread(For those not familiar: $_ is the default variable in Perl. Many operations use this variable if you don't specify one. You can use $_ like "it" in English: "Read in a line of input. If it ends in a newline..." In most languages, you would have to deal with "Read it into where?" and "If what ends in a newline?" But in Perl, if you don't specify where to read the line to, it goes into $_, and if you don't specify what you want to see if it ends in a newline, it checks $_, and so on...)
https://perlmaven.com/the-default-variable-of-perl
I agree with most everything the author says, along with the idea that you shouldn't use it that often.
----------
use strict; use warnings; use v5.10;
while ($_ = <STDIN>) { chomp $_; if ($_ =~ /MATCH/) { say $_; } }
----------
use strict; use warnings; use v5.10;
while (<STDIN>) { chomp; if (/MATCH/) { say; } }
For those not familiar, you can have the reader just discard an expression, so like (list 1 #;2 3) becomes (list 1 3), but you can handily comment out a giant function call or if expression or something while you work on it.
Scheme's nestable multiline comments are also nice. I'm not sure which language was first, but I think more languages are getting them now (Kotlin has them IIRC).
From that perspective it feels more natural.
[0]:https://en.m.wikipedia.org/wiki/Set-builder_notation
If I need a quick-and-dirty map over a list of something, a
is much nicer than a or whatnot that I have to do in C++.a.map(x => x + 1)
which is pretty nice. And Rust lets you do:
a.map(|x| x + 1)
C++ syntax is just awful, and especially for functional stuff.
In Ruby,
http://www.ai.sri.com/~pkarp/loop.html
http://www.lispworks.com/documentation/HyperSpec/Body/m_loop...
>>> int(‘x’, y)
...where x is the string/number you want to convert and y is the base.
I haven’t found a practical use case but it’s been a lot of fun to play with.
Also, it's available in many (most?) other languages: C (strtol), C++ (std::stoi), JavaScript (parseInt), PHP (intval), ...
Instead of:
listOfThings.foreach(x => println(x))
You can just type
listOfThings foreach println
Type inference is also great.
Scala in general has lots and lots of syntactic sugar, which is kind of the point of Scala.
Honroable mention:
Rubys &. operator
instead of
y = x.nil? ? nil : x.foo
y = x&.foo
Or just use a language which has some sort of null savety like Option types.
https://coderwall.com/p/jwzppw/the-existential-operator-in-c...
Depending on your stack it might be possible to make use of it already, e.g. Babel has a transpilation plugin, and Flow supports it for static type-checking.
At first I hated it because of how incomprehensible it was to someone coming from seemingly every other language, but I've started to use it more and more and wishing it existed in other languages.
It's especially useful for when the variable access is many characters. e.g. `if hackerNews.frontPage.votingCircleExists:` with nil checks is `if hackerNews && hackerNews.frontPage && hackerNews.frontPage.votingCircleExists`
and with & operator is: `if hackerNews&.frontPage&.votingCircleExists`.
Edit: I was mistaken, it's a little different. This is more like groovys safe navigation ?.
Slices that support negative indexes. List and dictionary comprehensions are amazing: { (X,Y): X2 + Y for X in range(10) for Y in someiter if Y > 5} I love that they become generators when you use () instead of []. Pure genius. Generators from a function containing yield or yield from equally beautiful. % for string interpolation was so good they had to bring it back. Tripple quotes using """ and ''' are hard to beat. Using func(list) to unpack a list into a functions arguments. Or func(dict) to unpack a map by name. Using args and kwargs to implimentaions variadic functions. I love indentation based code blocks. The way 'and' and 'or' can return values is so much better than a ?: terinary. I think I dumped a third of the Python spec there.
I could use a multi-line lambda but it's not a huge omission. Pipelines like bash | pipe or F# |> would be welcome.
go's select statement is also subtle but smart. Doing multiple waits in one thread is tricky to impossible in most any other language.
Built in regex like perl is always nice when you have it.
I'm sure I missed something gushing over Python, but tapping this out over the phone if already killing my thumb.
Java desperately needs groovys's safe navigation operator a?.getB()?.getC(). It's like a normal method call but returns null if the receiver is null instead of throwing an NPE.
> I love that they become generators when you use () instead of [].
I kind of like this, and I kind of hate it. My second-favorite language is Haskell, where everything is lazy, so to me it almost seems like everything should be generators anyway (except when a value is expected).
> % for string interpolation was so good they had to bring it back.
I hate % for string interpolation. It's ugly. Why do my variables need "variables" in the strings? It's indirect interpolation. I far prefer f-format strings, because `print(f"Correct: {correct}/{total}")` reads much better.
> Tripple quotes using """ and ''' are hard to beat.
Unconvinced. I feel like the syntax for multiline strings could be a bit simplified.
Also, it's a pain to combine multiline strings with indentation. I don't want all the extra whitespace at the fronts of the lines, but I also don't want to process the text immediately afterwards... sigh.
But I totally agree with the other points. Overall, the syntactic sugar is phenomenal! Just these points I disagree about.
I'm mostly still in Python 2.7 land so I forgot about the new f strings. I've never used them and I'm 50:50 only because I can do "%s %s %s" % (a.b(), z[:4], x2) without binding new variables. Can f strings do that? I don't know.
I agree about the whitespace issues. Have you seen a language do them better? I proposed using | to prefix each line for Java's string literals. At least they're explicit that way. I'm just glad Python used """ instead of backticks or or <<<START style here docs.
Something like that could be handled implicitly... hmm but that seems bad. Maybe you're right that having a choice is better!
> I can do "%s %s %s" % (a.b(), z[:4], x2) without binding new variables. Can f strings do that? I don't know.
In 3.x f-string style, `f"{a.b()} {z[:4]} {x2}"` would work just fine! Python just expects any expression inside the curly braces, so as long as you give up a value (and that value is either a string or an object of a class that implements `__str__`, I think), you're golden.
It's particularly useful when you have a lot of interpolation to do. The more arguments there are, the more tedious it is to read through a %-style format and figure out which variables correspond to what markers in the string.
> I agree about the whitespace issues. Have you seen a language do them better?
Not really, unfortunately.
I think a case could be made that all indentation should be based on either (a) the triple-quote or (b) the first non-whitespace character of the first line. But I don't know if that's intuitive enough. Definitely something to think about, though!
Apache Groovy also has shortcut property syntax so you can write `a?.b?.c` to get the same effect. Of course, all the syntactic sugar mixed together becomes quite confusing quite quickly. Some Groovers want to write the `?` once only and have it ripple through so you'd only need write `a?.b.c` in Groovy 3. But then, what if you actually want an NPE if `getB()` works but `getC()` doesn't? Perhaps `a?.b¿.c` would do the trick!
"=~" in Perl and globbing in shell are not syntactic sugar. They are fundamental parts of the languages.
For example, list comprehensions in Python: `[x^2 for x in L if x < 10]` is EXACTLY the same as `map(lambda x:x^2, filter(lambda x: x<10, L))`. The list comprehension is just easier on the eyes.
Except the former resolves to an actual list value, whereas the latter is a generator. (You would've been right if you'd used the generator syntax () instead of the list comprehension syntax []. Just thought I'd point it out since this whole thread is about syntax.)
The latter is an actual list value if you're still using Python 2:
A followup question to honor the important distinction: _do our favorite bits of beloved syntax tend to be core language or true sugar?_
I suspect core, since it would tend to be most well integrated. But perhaps sugar since it is created for the sole purpose of legibility and joy.
`a ||= b` sets a to b, unless a is already defined.
I see async/await as the only way to write asynchronous code that's readable
[foo, bar, ...baz] ES6 Destructuring