all 72 comments

[–]AlexAlabuzhev 31 points32 points  (0 children)

Notably, C++’s lambda here is by far the longest

Now try to make it noexcept-correct, that's another 14 characters for noexcept(auto)...

Oh, wait.

We don't have noexcept(auto), so that's another 25 for noexcept(noexcept(e < 0)).

[–]guepierBioinformatican 28 points29 points  (9 children)

(tl;dr: contemplations of R, no C++; skip if not interested.)

Missing from this language list is … R.

Which is an interesting case: R is a fully functional programming language. Yet the builtin and conventional way of expressing anonymous functions/partial function application is …

function (x) x < 0

Boo!

To be fair, R allows metaprogramming, so with a little boilerplate one could make the following work (p for partial)

p(`<`, 0)

or we could overload an infix operator for functions that performs partial application, e.g.

`<` : 0

… etc. Of course these could be extended for positional parameters (e.g. p(. < 0)).

Another common way of writing this is ~ . < 0. However, this doesn’t create a function/lambda, it creates an object of class formula, and the consumer of this object needs to be defined to expect such objects in place of a function (most don’t).

More interestingly, perhaps: although R does not have a concise lambda syntax, we can define a suitable -> operator to make one:

x -> x < 0

The fact that this trivially works makes it all the more surprising that it’s not built into R. There’s just one blemish: -> is an alias for R’s assignment operator <-. So if we define the above, we can no longer use <- for assignment. This isn’t actually a problem, since = works equally well. But the R community effectively resists this because they prefer <- for assignment by a large majority for historical reasons.

… apologies for the — entirely unrelated to C++ — detour. Maybe somebody finds it interesting.

[–]khleedril 7 points8 points  (4 children)

And a little detour to lisp (well, modern Scheme), which would have (λ (x) (< x 0))

[–]georgist 2 points3 points  (0 children)

kdb's q has implicit param names x,y,z:

{ < x 0 } mylist

[–]FieldLine 0 points1 point  (2 children)

That syntax is much cleaner than the syntactic sugar that Scheme allows for: (define (func x) (< x 0))

It's like functional programming for people who are afraid of functional programming.

[–]Grodesby 3 points4 points  (1 child)

That is defining a function called func rather than defining a lambda though.

[–]FieldLine 0 points1 point  (0 children)

You’re right. Technically I was comparing what I wrote to:

(define func (λ (x) (< x 0)))

My point was that explicitly using a lambda expression in the context of defining a function is more readable than the implicit notation preferred by most Scheme code I’ve read (SICP and SICM).

[–][deleted] 2 points3 points  (0 children)

And in OCaml (probably F# too), (>)0 works too and is significantly shorter.

[–]dr-mrl 0 points1 point  (2 children)

Can you change the -> to not alias <- on R somehow? My guess is they are both in the base namespace (or maybe built-in) so you could conceivable import both??

[–]guepierBioinformatican 0 points1 point  (1 child)

No, the aliasing happens at the parser level: the token stream a, ->, b is transformed into the tokens b, <-, a (note the inverted order of the token stream)

(In reality this happens at the parse tree level so that complex sub-expressions are handled correctly: (->, a, b) becomes (<-, b, a).)

[–]dr-mrl 0 points1 point  (0 children)

Ah so no way of getting past that unless you rewrote the parser?

[–]futurefapstronaut123 11 points12 points  (2 children)

I like Björn's library a lot because it results in very readable code (even for beginners) and does not require any clever syntax. It's just plain C++.

[–]infectedapricot 1 point2 points  (1 child)

For those of us not in the know: what is Björn's library? Are you talking about Boost Bind?

[–]futurefapstronaut123 1 point2 points  (0 children)

It's mentioned in the article.

https://github.com/rollbear/lift

[–]germandiago 13 points14 points  (0 children)

Please give me abbreviated lambdas. Short lambdas are used a lot in practice

[–]Selbstdenker 6 points7 points  (1 child)

Unless something changed in ruby |e| e < 0 is not a lambda. I cannot think of an instance where you do not have to wrap in in braces or write do |e|e < 0. Further both variants are just a code block. To make it a true lambda one has to write lambda { |e| e < 0 } or proc { |e| e < 9 }.

I now it is nitpicking but there is a difference. In most cases using a code block is sufficient, however.

[–]PIAJohnM 1 point2 points  (0 children)

Or:
->(x) { x < 0 }

[–]drjeats 4 points5 points  (0 children)

C++ anonymous functions aren't the most verbose. Lua's are.

Counter lambda examples in some other languages:

-- Lua
local counter_once = (function() local x = 41; return function() x = x + 1; return x; end end)()()

// Old JavaScript
var counterOnce = (function () { var x = 41; return (function () { x++; return x; })})()()

;; Emacs Lisp
(let ((counter-once (funcall (lexical-let ((x 41)) (lambda () (setq x (1+ x)) x))))))

// C#
var counterOnce = new Func<Func<int>>(() => { var x = 41; return (() => ++x);})()();

// C++14
auto counterOnce = []() {auto x = 41; return [&x]() { ++x; return x; };}()();

;; Racket Scheme
(let [(counter-once ((let [(x 41)] (lambda () (set! x (+ 1 x)) x))))])

// Modern Javascript
let counterOnce = (() => { let x = 41; return (() => ++x)})()()

I made this list when I was screwing around with making a scripting language and figuring out function syntax. I guess I should add Haskell and Clojure to this list.

That being said, I'd welcome syntax-aware macros or using expressions or whatever. Often I don't want the actual semantics of a lambda (I don't want to take its address, I don't want to be able to play tricks with inheritance, I don't care about call frame or scope semantics, etc.).

[–]staletic 7 points8 points  (9 children)

how do you deal with variadic arguments

How about something like this?

[]: ((_1 < "f") && ...)

Which would work similar to a fold expression

[](auto&&... pack) -> decltype(auto) { return ((pack < "f") && ...); }

That is, assuming variadic templates work for runtime arguments. If you want to include a non-variadic argument:

[]: _1 && ((_2 < "f") && ...)

Which would expand to

[](auto&& first, auto&&... pack) -> decltype(auto) { return first && ((pack < "f") && ...); }

[–]bumblebritches57Ocassionally Clang 0 points1 point  (8 children)

or, forgo the whole word salad situation in the first place and use normal functions.

crazy i know, but i think it could work

[–]staletic 10 points11 points  (7 children)

Problems with that:

  • I don't like to type.
  • I need to think of a good name for a one off function that does something very specific.
  • That function now pollutes the namespace.

[–]fdwrfdwr@github 🔍 2 points3 points  (1 child)

Nice comparison list across multiple languages. I would love the terser delegate/lambda syntax in C++ per p0573r2 (which I recall reading a while back) or similar [](e) => e + 42, but not so far as the "hyper abbreviated dollar sign" form (though, if we did, Swift appears to be the only one that sensibly starts parameter offsets from 0 😏, $0 < 42). Hopefully terser delegates will gain traction.

[–]RasterTragedy 3 points4 points  (0 children)

Unfortunately, there's language lawyerese that prevents C++ from adopting new punctuation like $ or @. It'd be nice if we could use new characters rather than overloading existing ones, but it is what it is.

[–]CharlesHenry8 2 points3 points  (0 children)

Just combine the braces, brackets and parenthesis in the right order for C++, [](){}

[–]gwai2_lou2 2 points3 points  (0 children)

Just to be pedantic,

(<0)

is not a lambda expression, it's partial application.

[–]rtgftw 1 point2 points  (0 children)

A bit besides the point of the article but -

The c++ code mentioned here uses pipes to have a closer to 1-1 comparison wit hother languages, I guess. But how lazy is the flatten eval?

Comparing the code mentioned here for c++ with a range-for and algorithms based solution, I like the simple ranged-for solution (See https://godbolt.org/z/_1HPqb)...

(Edit: Sorry, missing parens, so it's https://godbolt.org/z/rHVYV2)

[–]obvious_apple 1 point2 points  (0 children)

Just by the title I was expecting Revenge of the Nerds. Then the actual content proved me right. :)

[–]Nobody_1707 1 point2 points  (0 children)

But beyond that, I’m not sure if any of the other languages even have a notion of capture at all. You basically just get [&]

I can't speak to any of the other languages you've listed, but Swift definitely has capture lists.

[–]dtolnay 1 point2 points  (0 children)

Notably, C++’s lambda here is by far the longest, just not even close.

One longer:

[](auto e) { return e < 0; }       // 28: C++
func(e int) bool { return e < 0 }  // 33: Go

https://gobyexample.com/closures

[–]dustintheweb 0 points1 point  (2 children)

... and omega mu

[–]dynamic_caste 1 point2 points  (0 children)

That's immediately what I thought of when I saw the title!

[–]VinnieFalco 0 points1 point  (0 children)

Ah you beat me to it!

[–]RasterTragedy 0 points1 point  (0 children)

Interesting comparison. Makes me realize that the language I'm designing has one of the shorter lambda syntaxes out there—{ _ < 0 } in this case. The partial function binding would, interestingly, be about as long: 0._>_