
Ask HN: Your favorite syntactic sugar from any language? - davegauer
Most programming languages I&#x27;ve encountered, no matter how otherwise unappealing, have at least one syntactic feature that makes them really pleasurable for at least <i>some</i> type of task.<p>Some things I miss when I don&#x27;t have them are:<p>* &quot;=~&quot; for regex matching (as in Perl and Ruby)<p>* &quot;{foo:[&#x27;bar&#x27;,&#x27;baz&#x27;]}&quot; for quick data structures (as in JavaScript)<p>* &quot;for f in *; do echo $f; done&quot; for looping over a &#x27;glob&#x27; of files (as in Bash)<p>What&#x27;s your favorite bit of sugar?
======
jwilk
Syntactic sugar is not another name for "really cool syntax". They are non-
essential constructs, which could be removed without much effect on the
language, except for readability.

"=~" in Perl and globbing in shell are not syntactic sugar. They are
fundamental parts of the languages.

~~~
garmaine
To follow on from this, "syntactic sugar" is a permitted short-hand that can
be losslessly transformed into another, often more verbose construction. This
is why it must, definitionally, add no new features.

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.

~~~
DonaldPShimoda
> `[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))`

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

~~~
Sohcahtoa82
> Except the former resolves to an actual list value, whereas the latter is a
> generator.

The latter is an actual list value if you're still using Python 2:

    
    
      pi@raspberrypi ~ $ python
      Python 2.7.3 (default, Nov 24 2017, 21:13:24)
      [GCC 4.6.3] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> map(lambda x: x^2, filter(lambda x: x < 10, [1,2,3]))
      [3, 0, 1]
      >>>
      pi@raspberrypi ~ $ python3
      Python 3.2.3 (default, Mar 25 2017, 13:24:50)
      [GCC 4.6.3] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> map(lambda x: x^2, filter(lambda x: x < 10, [1,2,3]))    
      <map object at 0x76a72570>

~~~
DonaldPShimoda
Right, you're quite correct! I assumed OP was using Python 3 since that's the
current version, and their statement would have been true in 3 with the small
change I suggested. Their point is still correct overall, but if they're going
to make an example from an older version of the language I think they ought to
specify as much.

~~~
garmaine
Python 3 is a different language :)

------
artemisyna
Haskell has way too much syntactic sugar some of the time, but I really
appreciate its anonymous function syntax.

If I need a quick-and-dirty map over a list of something, a

    
    
      (\x -> x + 1) a
    

is much nicer than a

    
    
      std::for_each(a.start(), a.end(),
       [](float x) {  
                return x + 1;  
            } // end of lambda expression  
       )
    

or whatnot that I have to do in C++.

~~~
nicoburns
JavaScript lets you do:

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.

~~~
himom
Swift closure syntax, at least in <= 2.0, made for awkward API calls, since it
wasn’t clear whether inline or after closures were used.

In Ruby,

    
    
        a.map(&:succ)

~~~
steveklabnik
If you have a named function, rust lets you do

    
    
        a.map(succ)
    

as well, since functions can be used where closures can, as long as the types
work.

~~~
jeffmcmahan
Same in JS

------
kjeetgill
I love love love almost everything about Python's syntax.

Slices that support negative indexes. List and dictionary comprehensions are
amazing: { (X,Y): X __2 + 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.

~~~
DonaldPShimoda
I love Python too (a lot), but I disagree with some of these.

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

~~~
kjeetgill
Eager lists have their place! Ya can't sort or slice into a generator. I like
the choice.

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], x __2) 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.

~~~
DonaldPShimoda
> Eager lists have their place! Ya can't sort or slice into a generator. I
> like the choice.

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!

------
rehemiau
Pipeline operator ( |> ) in functional programming languages (Elixir, F#, Elm)

------
hprotagonist
I really like C#'s => operator, especially in the context of expression-body
members.

    
    
      public override string ToString() => $"{fname} {lname}".Trim();
    

I am overjoyed with newer python's f-strings.

    
    
      foo = 5
      bar = 4.5005
      print(f'foo is {foo} and the first bit of bar is {bar:0.2f}')
    

I really like python's * and ____* unpacking, and especially that you can do
it in the middle with throwaways:

    
    
      first, *_, last = function_that_returns_ten_things()
    

or for building kwarg-only classes from dicts:

    
    
      foo = {'x':5,'y':6}
      bar = Point(**foo)

------
AnimalMuppet
The defaults in Perl, especially the default variable.

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

~~~
ramses0
This is worth a bit of explanation, see this link and the code duplicated
below:

[https://perlmaven.com/the-default-variable-of-
perl](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; } }

------
fvdessen
I really like python's array slices, a[5:] b[2:3], and list comprehensions, [x
* 2 for x in array if x > 0]

~~~
Pete_D
I love Python comprehensions. I _want_ to dislike Python - significant
whitespace, weak lambdas, other trivial complaints - but the comprehensions
are so nice, especially combined with yield and the iteration protocol, that
it's usually the first language I turn to. There's syntax for sets, dicts, and
generators too:

    
    
        >>> { char.upper() for char in "hello" }
        set(['H', 'E', 'L', 'O'])
        >>> { char: ord(char) for char in "world" }
        {'d': 100, 'r': 114, 'o': 111, 'w': 119, 'l': 108}
        >>> (char for char in "foobar").next()
        'f'

~~~
Tijdreiziger
What I really dislike about comprehensions is that the for syntax comes at the
_end_. They would be much easier to parse if it came at the beginning.

~~~
kjeetgill
I used to feel that way too. When you write out nested for loops the work is
at the other end! For what it's worth, it is meant to resemble mathematical
set builder notation. I think that familiarity turned me around on it (pun
intended).

From that perspective it feels more natural.

[0]:[https://en.m.wikipedia.org/wiki/Set-
builder_notation](https://en.m.wikipedia.org/wiki/Set-builder_notation)

------
LordHeini
Beying somewhat of a functinal fanboy i really like Scalas (and oder functinal
languages) point free style.

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.

------
ioddly
Scheme's expression comments are really quite handy, but only possible to
implement in languages where everything is an expression.

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

~~~
EvenThisAcronym
D has also had them since the early 2000s.

------
christophilus
For me, it's Clojure's threading macros. They're like the `|>` operator on
steroids. Also from Clojure, the ability to use maps and keywords as functions
in a lot of cases, such as: `(map :hello [{:hello "world"}]) ; ["world"]` and
`({:hello "world"} :hello) ; "world"` It comes in really handy more often than
I would have thought.

------
Pete_D
Common Lisp's LOOP macro is a fearsome beast.

[http://www.ai.sri.com/~pkarp/loop.html](http://www.ai.sri.com/~pkarp/loop.html)

[http://www.lispworks.com/documentation/HyperSpec/Body/m_loop...](http://www.lispworks.com/documentation/HyperSpec/Body/m_loop.htm)

------
kendallpark
Ruby inline conditionals. They read like English. Short and sweet.

    
    
      if condition?
        return
      end
    
      if !i_probably_shouldnt?
        do_something
      end
    

Becomes:

    
    
      return if condition?
    
      do_something unless i_probably_shouldnt?

~~~
derefr
When writing one-off Ruby scripts, I especially like using the single-line
unless with Kernel.fail:

    
    
        fail "bad arg" unless dir = ARGV.shift
    

(If you could figure out a way to _also_ stuff that line with a transformation
to a Pathname for not-nil results, I'd be in heaven.)

~~~
jitl
Takes a bit of setup to monkey-patch String, but:

    
    
        class String
          def to_pn
            Pathname.new(self)
          end
        end
         
        fail "bad arg" unless dir = ARGV.shift&.to_pn

------
himom
Technically, any Turing-complete language can be mapped to any other Turing
complete language, so it’s possible to have non-trivial syntatic sugar do
anything. (Use brainfuck as IR, lol.) >:) But yeah, SS is more like:

    
    
        ++x; // x = x + 1 
    

Nifty syntax

    
    
        &:foo           Ruby method name to callable syntax
    
        foo&.bar        Ruby check nil before calling bar
    
        foo?.bar        Swift optional presence check 
    
    
        if(x = foo!.bar!) {
             x.something()
        }
    
    
        foo ?? bar      Swift nil-coalescing
    
        foo || bar      Ruby nil-coalescing    
    
        <<1,4,8,45>>    Erlang bit syntax (binary literals), with typing and endianess
    
        5b432140        Erlang arbitrary base literals
    
        List comprehensions Erlang, Python, 
    
        Binary comprehensions in Erlang
        2> Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>.
        <<213,45,132,64,76,32,76,0,0,234,32,15>>
        3> RGB = [ {R,G,B} || <<R:8,G:8,B:8>> <= Pixels ].
        [{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
        -- from LearnYouSomeErlang
    
        Show anon fn’s in many languages using utf8 λ.
    
        Swift property lifecycle callbacks

------
Doxin
I'm absolutely positively in love with "Universal function call syntax" from
D, it makes the following:

    
    
        foo.bar(baz)
    

compile to the following if foo has no property bar:

    
    
        bar(foo, baz)
    

It allows you to trivially extend classes from libraries without meddling with
their code or breaking other code using the library. e.g. if you define:

    
    
        string helloWorldize(string input){
            return "Hello, "~input;
        }
    

You can then do this anywhere "helloWorldize" is in scope:

    
    
        "bob".helloWorldize();
    

And because of the strong type system and smart compiler you'll never run into
situations where you call helloWorldize when you don't mean to.

------
city41
I miss CoffeeScript's existential operator now that all my projects are
standard ES6.

[https://coderwall.com/p/jwzppw/the-existential-operator-
in-c...](https://coderwall.com/p/jwzppw/the-existential-operator-in-
coffeescript)

~~~
jamesisaac
This is currently a stage 1 proposal for the core language:
[https://github.com/tc39/proposal-optional-
chaining](https://github.com/tc39/proposal-optional-chaining)

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.

------
ralston
Python 3.5+

    
    
      >>> first = {"a": 1}
      >>> second = {"b": 2}
      >>> merged = {**x, **y}
      >>> print(merged)
      {"a": 1, "b": 2}

~~~
tylerhou
Same exists in ES6:

    
    
        const first = { a: 1 };
        const second = { b: 2 };
        const merged = { ...first, ...second };
        console.log(merged) // { a: 1, b: 2 }

~~~
Doxin
Python had it first ;)

------
frfl
Sorry, this comment will not really benefit the matter at hand, but I'd like
to share a relevant quote I quite enjoyed when I first read it

> Syntactic sugar causes cancer of the semicolon. \- Alan Perlis

------
snarfybarfy
Multiline strings aka 'here documents' in most Shells.

Rich datastructure literals in Clojure for sets #{'foo'}, maps {:a 1, :b 2},
lists (1,2,3) vectors [1, 2, 3]

The serialization format EDN is basically JSON on steroids.

[https://github.com/edn-format/edn](https://github.com/edn-format/edn)

------
laogai
Ruby's & operator.

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

~~~
christophilus
Agreed. Null conditional operators are definitely handy in languages that have
nulls. C# has this in the form of ?.

~~~
kjeetgill
This is there piece of C# I'm most envious of missing out on in Java.

------
ezekg
Python/Ruby's kwargs, JavaScript's destructuring syntax, Python list
comprehensions, Ruby's array push << method, ranges, and literal array
expressions

------
nunez
Ruby’s question marks for Boolean functions and exclamation points for
mutating ones. I didn’t get t at first, but once I did, I was in love. Perfect
for readabiiity.

~~~
DonaldPShimoda
Do you mean like functions named `is_empty?` and `set_value!`? If I've been
told right, this comes from Scheme. I first experienced it in Racket, and I
absolutely love it. It's seriously one of the greatest conventions.

------
snappyTertle
Destructuring in almost any functional language and ES6 JS.

------
amthewiz
Ruby's optional parenthesis for function calls. Makes beautiful DSLs like
RSpec -

    
    
      describe UsersController do
        before do
          allow(controller).to receive(:current_user).and_return(nil)
        end
    
        describe "GET #new" do
          subject { get :new }
    
          it "returns success" do
            expect(subject).to be_success
          end
        end
      end

~~~
kjeetgill
But I love the brace free dsl. It's pretty. How van you tell how many tokens
it takes? Describe or subject take? It's a bit hard to parse, but I don't know
Ruby.

Coming from Python the end end end hurts though. Why not just use braces then?

------
EvenThisAcronym
Hands down, it's D's shorthand array operations.

    
    
        int[] a = [1, 2, 3];
        int[] b = a[] * 3;
        assert(b == [3, 6, 9]);
    
        a[] += 2;
        assert(a == [3, 4, 5]);
    
        int[] c = a[] + b[];
        assert(c == [6, 10, 14]);
    

This of course works with D's slicing syntax so you can do stuff like a[0..1]
*= 3.

------
mabynogy
I use "star" in my programming language to "dereference" generators (run them
until they are finished). For example:

    
    
      //block for 4s
      sleep* 4
      
      //run a modal form
      let* ok form_confirm "Do you agree?"
    

Those calls are converted to loops.

------
singularity2001
I love kotlin lambdas with «it»:

list.filter{ it > 3 }.map{ it + 1 }

compare that to shitty Java or C++

.

Love js map construction by name:

fun="..."; map={fun}; map.fun == "..."

Nice lambdas and properties are the things I miss most in python, especially
python3, where you have to call list(map(...)) all the time (generators are a
good idea but _why_ not add proper __str__?)

------
jedberg
Python list comprehensions.

They could be written as multiline loops, that are definitely more readable,
but it's just so nice to whip out a list comprehension sometimes:

    
    
        print([int((((1 + 5**0.5) / 2)**n - ((1 - 5**0.5) / 2)**n) / 5**0.5) for n in range(1, 21)])

------
farleykr
I just discovered being able to use Python to convert a number to a different
base:

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

~~~
jwilk
It's not a syntactic feature, so it can't be syntactic sugar.

Also, it's available in many (most?) other languages: C (strtol), C++
(std::stoi), JavaScript (parseInt), PHP (intval), ...

------
domlebo70
Do notation in Haskell, Scala etc. Nothing else comes close

~~~
tylerhou
You don't need do notation in an imperative language, though.

~~~
imh
You don't need the IO or state monads in other languages, but that's not the
only useful monad. Applicative functors with their own do notation are pretty
cool too.

------
timwis
JavaScript's async/await is our reward for suffering promises. Not perfect,
but makes the language a lot more approachable IMO.

------
AndrewDucker
The one that's saved me the most time is probably "foreach" as a way of
accessing enumerables in c#.

Simple, readable, and easy.

------
nemoniac
If you use pretty much any lisp-like language you can add your own favourite
syntactic sugar to the language yourself.

------
charlieflowers
possibly async/await

------
RhysU
Haskell dollar operator ($). Last I checked, it fits into the Python grammar
if anyone feels PEPpy.

------
tu7001
List comprehension - Python, Haskell.

------
emorning2
async/await

I see async/await as the only way to write asynchronous code that's readable

------
geoelkh
A lot of things in Ruby like

if !disabled //instead of unless disable

------
imh
Python 3's string formatting is pretty useful.

------
aqme28
Ruby's ||=

`a ||= b` sets a to b, unless a is already defined.

------
pdgonzalez872
The pipe operator in Elixir.

------
BigToach
Decorators in any language.

------
aphextron
range() in Python

[foo, bar, ...baz] ES6 Destructuring

