Remix.run Logo
▲ Yet another way to invoke functions without parentheses(blog.ikaes.de)
205 points by aragonite 3 days ago | 80 comments
▲hans_castorp 6 hours ago | parent | next [-]

This reminds me of "Creators admit Unix, C hoax" (e.g. https://www.gnu.org/fun/jokes/unix-hoax.html)

> We stopped when we got a clean compile on the following syntax:

    for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
▲nathell 5 hours ago | parent | next [-]

How Perl was created:

‘Larry, throw the cat at the keyboard!’

MEEEOW!

‘What did it type?’

‘&}Ak'>v=4%Qe}9;’

‘OK, so let’s make this a syntax for hello world.’

▲bjoli 4 hours ago | parent | next [-]

There was a hilarious video in The early days of YouTube when someone tried to write Perl using vistas voice recognition.

I haven't seen it in many many years, but at the time it struck my giggle button every time.

▲layer8 3 hours ago | parent [-]

https://m.youtube.com/watch?v=MzJ0CytAsec

▲mock-possum 23 minutes ago | parent [-]

Oh wow it’s an actual video of hell!

▲saghm 4 hours ago | parent | prev | next [-]

OCR works too https://www.mcmillen.dev/sigbovik/

▲marcosdumay 39 minutes ago | parent | prev | next [-]

There's always this amazing paper:

https://www.mcmillen.dev/sigbovik/2019.pdf

▲shawabawa3 an hour ago | parent | prev | next [-]

I was very disappoint to learn that '&}Ak'>v=4%Qe}9;' is not actually hello world in perl :(

here's an actual one: print'(%,,/@(/),$!'^'`@@@@`_@[@@+'

another one

    $/=~s##'&}(/%]?`~=.&~(@^,_!$/"'^'+.{|}!_{.|=.^_/,@;'^'}!:=,^(~<-|$'#ee
▲shevy-java an hour ago | parent | prev | next [-]

I also often blame it on my cat, but unfortunately, the truth is simpler ... Larry was inspired by awk. So this is why perl is snoopy swearing.

▲nullsanity 4 hours ago | parent | prev [-]

I did genuinely try to run this since, well, it could be true, I don't know Perl.

Bareword found where operator expected (Missing operator before "Ak"?) at -e line 1, near "&}Ak" Bad name after Ak' at -e line 1.

▲1718627440 2 hours ago | parent [-]

How to trick nerds into installing your spyware 101.

▲akavel 2 hours ago | parent | prev [-]

Well, the prank is being refined for many years now, by the fine folks partying at:

https://www.ioccc.org

▲lifthrasiir 44 minutes ago | parent | next [-]

In fact that line in question does come from an IOCCC winner: https://github.com/ioccc-src/winner/blob/master/1985/shapiro...

▲a4isms an hour ago | parent | prev [-]

In the late 90s, I interviewed for a job as a Technical Product Manager with a Toronto startup. The CTO/Co-founder, was an obfuscated C contest winner: https://www.ioccc.org/1985/lycklama/index.html

Great guy to work with. I think he runs a craft brewery now.

▲nathell 5 hours ago | parent | prev | next [-]

I love this. This is a fun hack, but the article also hearkens back to pre-LLM days when people were still interested in _code_.

▲bunderbunder 4 hours ago | parent | next [-]

I wonder if there was a period in the 90s where the chess community was more interested in talking about IBM’s stock price than in actually playing chess.

▲parhamn an hour ago | parent [-]

"Delivering chess solutions" was never the job though.

▲stymaar 4 hours ago | parent | prev | next [-]

I'm definitely gonna use that for April 1st though, just adding this as instruction in Claude.md

That will also serves as a litmus test to check how many of my coworkers are reading the code they push.

▲stigok 5 hours ago | parent | prev | next [-]

Programmers are still interested in code

▲cm2187 5 hours ago | parent [-]

Weekend hobby!

▲mystifyingpoi 5 hours ago | parent [-]

Now there is Monday again, no more coding, back to babysitting agents.

▲kpcyrd 2 hours ago | parent | prev | next [-]

It feels like it's from back when we unironically thought memorizing quirks like this makes us better programmers, or is somehow important for making computers more secure, aka middle of the 2010s tech bubble.

▲idkfoekfkdcjjs 3 hours ago | parent | prev [-]

Ah yeah, here we go…

“Back in my days…”

“No true Scotsman…”

“I remember when…”

“Kids these days…”

Gotta love this self-aggrandising humble-brag nonsensical stuff.

▲amelius 4 hours ago | parent | prev | next [-]

I want to put the called function after the arguments:

    (((x)f)g)h
So I can see exactly the order in which things happen, from left to right. As opposed to:

    f(g(h(x)))
where I have to read backwards.
▲taolson 7 minutes ago | parent | next [-]

In a lazy language like Haskell, the order in which things are actually evaluated is f -> g -> h -> x, because arguments to a function are only evaluated when the are needed, rather than before they are called. But even so, I still prefer writing it as x |> h |> g |> f.

▲bunderbunder an hour ago | parent | prev | next [-]

One of the things I love about programming in dialects of ML like ocaml and f# is the forward pipe operator:

  x
  |> f
  |> g
  |> h

It's nice because it just puts whatever's on the left of the operator in as the last argument. So it also works for functions with an arity of more than one.

So if it were something like

  h(z, g(y, f(x))
you can write it as

  x
  |> f
  |> g y
  |> h z

It works really nicely for data munging code:

  my_data
  |> filter (x => x > 37)
  |> select (x => x * 2)
  |> sum
but unlike doing it with method calls in object oriented code, inserting a new function into the chain doesn't involve modifying a class or or mucking around with more complex language features like extension methods and traits.
▲pfdietz an hour ago | parent [-]

Lisp macros let you do similar things, and you don't have to change the language itself.

▲tomsmeding 39 minutes ago | parent | next [-]

In ML family languages you also don't have to change the language for this, as function application is naturally "argument-by-argument" (the term is "curried"): the syntax is normally f x y z but (f x y) z and (((f)) (x)) y z are just as valid, and indeed f x y will be a function taking one argument. Thus |> can just take a function of one argument and be done.

▲bunderbunder an hour ago | parent | prev [-]

Maybe I've just been doing too much Racket lately and that's affecting how I view things, but it's real hard for me to not think of lisp macros as a mechanism for changing the language itself. Especially if it's something like a reader macro.

▲ktpsns 4 hours ago | parent | prev | next [-]

Mathematica has a crazy amount of syntax abbreviations (https://reference.wolfram.com/language/guide/Syntax.html). Of course your whish is fulfilled there: x // f called the postfix operator.

▲danlitt 4 hours ago | parent | prev | next [-]

Do you mean (((x)h)g)f ?

since the order in which things happen is "h first, then g, then f"

▲mesrik 2 hours ago | parent | prev | next [-]

So would you like to write shell commands connected with pipes like that too?

So is this better too

  $ less | find / -type f -perm /6000 -ls
than ?

  $ find / -type f -perm /6000 -ls | less
Just because shell actually starts executables right to left when using pipes. Reason to this behaviour is because it can fail early if there is problem constructing pipe first and not spend lot of time something finding later that some pipe components can't start and receive data properly.

ps. I'm fine with current notation and would not like change it.

▲unilynx an hour ago | parent [-]

I think he actually wants pipes. Instead of having to write:

  f3(f2(f1(some data)))
it would be nice to write

  some data |> f1 |> f2 |> f3
javascript has proposals for pipe operators because as soon as the simple .map /.filter/.reduce APIs don't suffice (ie. as soon as Promise.all is needed) the f3(f2(f1(data))) mess starts.
▲BeetleB an hour ago | parent [-]

F# for the win!

▲adverbly 3 hours ago | parent | prev | next [-]

That actually makes so much sense...

When you're calling a function, you're putting some things into the function... You have to get the things first before you can put them in...

Why didn't it evolve like that in the first place? Is it a byproduct of mathematical notation? If so, I wonder why mathematical notation evolved that way in the first place...

▲baruchel 3 hours ago | parent | next [-]

Forth (or Postscript by the way) works exactly like that, but writing the function first also makes sense in functional programming, specifically when you care about currying functions: writing "f(g(h(x)))" (or "f g h x" or whetever) makes more sense, since you are not supposed to put all expected arguments at once.

▲arethuza 2 hours ago | parent [-]

Do you have to write a function first before it is referenced in PostScript? (I did a lot of PostScript programming in NeWS once - but it was ~35 years ago...)

▲stronglikedan 3 hours ago | parent | prev [-]

> Why didn't it evolve like that in the first place?

It did, just in Arabic.

▲nine_k 3 hours ago | parent | prev | next [-]

Did you even have an RPN-based calculator at school?

As to more serious programming languages, Erlang, F#, Haskell have forms of a "pipe" operator, roughly

  [1 2 3] |> sum |> print
For it to work properly, functions should be either functions of one argument, or support currying.

But the original algebra functions, as introduced by Leibniz in 17th century, were, of course, pure functions, more like properties than procedures. So cos(x), aka cos x, is just a formalized shorthand for "cosine of x", so it preserved the order of words typical for Germanic and Romance languages. Maybe if functions were introduced by the Japanese, we would have the reverse order, kind of x の cos.

▲rafaelRiv 2 hours ago | parent | next [-]

This has been proposed but never adopted : https://github.com/tc39/proposal-pipeline-operator

▲macintux 2 hours ago | parent | prev [-]

I think you mean Elixir, unless Erlang added a pipe operator in the last 10 years...good grief I've been out of that world too long.

▲ashkankiani 3 hours ago | parent | prev | next [-]

Stack based languages and the APL tradition all follow this pattern, which I agree can be more terse and nice too. I've also been experimenting with right-associative calls which does the same thing but in reverse. For a data pipeline you're more likely to transform from A->B, so I think the post-fix syntax makes sense.

But you can also define a "thread" operator easily for doing subsequent function calls. ala `threaded x { f; g; h }`

▲skocznymroczny 3 hours ago | parent | prev | next [-]

Assuming you mean h)g)f, you can do it in D. D allows you to write this:

f(g(h(x))) as x.h().g().f() or even x.h.g.f (parenthesis are optional).

▲layer8 3 hours ago | parent | prev | next [-]

If `f` is an expression, that would require it to be evaluated last as well.

▲account42 3 hours ago | parent | prev | next [-]

This is why some languages have the | pipe syntax for chaining operations.

▲raverbashing 3 hours ago | parent | prev | next [-]

And that's why "purely procedural" languages don't make much sense to me

It's more natural to write

    x.h().g().f()
▲kiicia 2 hours ago | parent | prev | next [-]

you can start with

    var chain = x=>f=>f?chain(f(x)):x;
    chain(x)(h)(g)(f)();
if you need to partly curry to free first argument

    var _ = (f,...y)=>x=>f(x,...y);
    var sum = (x,y)=>x+y;
    chain(1)(_(sum,1))()
if you want whole pipeline

    var $ = (x,...f)=>f.reduce((x,f)=>f(x),x);
    $(1,_(sum,1));
which gives fun ability to extract function without input param

    var sum1 = _($,_(sum,1));
    sum1(1);
... which in turn is just having fun with point-free JS
▲anal_reactor 3 hours ago | parent | prev | next [-]

I want to put the function below the arguments, so that the call tree actually looks like a tree

    u v x y
     f   g
       h
This is h(f(u,v), g(x,y)).
▲Rohansi 3 hours ago | parent | prev [-]

The function reference is actually evaluated first so your preferred order is actually backwards! Consider this:

  foo.bar(x)
The `foo.bar` field has to be retrieved before the function can be called. It does not evaluate `x` first. That is observable with JS proxies, or you can test with code like this:

  foo()(bar())
▲LtWorf 3 hours ago | parent [-]

Executing the "." operator isn't the same as executing the function.

▲Rohansi 2 hours ago | parent [-]

JS and many other languages have getters so that's not always true.

But my point is that the reference to the function you are calling is actually its own term that needs to be considered in the order of evaluation.

You can also use the IIFE (immediately invoked function expression) pattern that is/was common in JS as an example:

  (function() {
    // ...
  })();
You can use any valid expression in place of a function name, including anything that causes observable side effects.
▲LtWorf 36 minutes ago | parent [-]

A "getter" executed on the "." operator isn't the same as executing the function it returns anyway.

▲MattCruikshank 3 hours ago | parent | prev | next [-]

I want to write a super pedantic book showing every way I can think of to move data from here, to there. In the same program, or between programs.

Global variable.

Parameter to a function.

Pass a functor/lambda, get the value.

Environment variable.

Registry.

File.

Store it in a ping response.

VRAM texture that you write and then read.

Database.

REST server.

I'm pretty sure I could come up with a thousand ways.

But... why? Why do I want to write this book? Why has it been on my mind?

▲vvill an hour ago | parent | next [-]

Reminds me of Harder Drives https://tom7.org/papers/murphy2022harder.pdf

And something my friend wrote a few years ago: https://github.com/radian628/tram

Data storage and transmission has so much innovation going on!

▲CoastalCoder 2 hours ago | parent | prev | next [-]

You might be interested in the book "Data Flow Analysis" by Khedker et al.

It's very compiler-focused, but it's one piece of the puzzle.

▲arethuza 2 hours ago | parent | prev | next [-]

For some reason this made me think about all of the potential complexities that can be involved in CLOS in calling a generic function and some method(s) actually being invoked...

▲fwip 2 hours ago | parent | prev [-]

Implement your own delay-line memory with the speaker, microphone, and echo of the room.

▲pards 6 hours ago | parent | prev | next [-]

Off topic: This website looks like a ransom note

▲eviks 4 hours ago | parent [-]

Maybe it is, just requires a different parser

▲CrendKing 5 hours ago | parent | prev | next [-]

Not gonna work on Firefox, since according to the doc, Error.prepareStackTrace is an optional API and only implemented by V8.

▲fg137 5 hours ago | parent [-]

> optional API and only implemented by V8

aka "Chrome implemented this and wanted everyone else to do so as well"

▲TheSilva 6 hours ago | parent | prev | next [-]

  Object.prototype.message='alert\x281337\x29';Array.prototype.toString=Error.prototype.toString;Error.prepareStackTrace = Function;const x = new Error;x.valueOf=x.stack;+x;
Well, that's a mouthful! So many years and JavaScript still can do the most amazing, weird, awesome, scary, obscure, and sexy things in the world of coding.
▲fg137 5 hours ago | parent | next [-]

The prototype thing is quite unique among mainstream languages. It is kind of simple in principle and works well for what it intends to do, but god it causes so much confusion and is frequently a source of CVEs. valueOf combined with implicit conversion is a nightmare for production code.

▲customguy 5 hours ago | parent | prev [-]

Yesterday I was re-using some shaders I had written a long time ago, and here's what I used to do multiline strings before the glorious backtick arrived on the scene...

    (function () {/*
      my awesome shader code
    */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]
... I can't call it sexy, but I also can't deny I felt a mixture of fear and arousal when I saw that.
▲annex-winged-cr 4 hours ago | parent | next [-]

TIL about [^], never seen that before. Apparently, it works like a dot but it also matches newlines.

▲chii 3 hours ago | parent | next [-]

I believe this is the regular syntax for a set of characters (between "[" and "]"), but the caret symbol ("^") is negation when used inside the set. Therefore, it is simply the negation of an empty set of characters.

▲gmac 4 hours ago | parent | prev [-]

Oh, me too. I’ve previously used [\s\S] for that.

▲h43z 4 hours ago | parent | prev [-]

Pretty interesting that you can carry comments over.

    (x=>/*this is a comment*/1) + 1
    "x=>/*this is a comment*/11"
I wonder if anything cool can be done with it today. It's probably useless.
▲CreepyHunterX an hour ago | parent | prev | next [-]

This is a creative hack, and here’s where it actually matters. Blocklist-based sanitizers and WAFs typically work by matching a string or a regex, so this type of hack usually slips past them. I found this class of XSS in audits in telemetry fields that were protected by a regex blocklist. The actual fix was not just a longer blocklist, but context-aware output encoding (plus a CSP as defense in depth).

▲semiquaver 6 hours ago | parent | prev | next [-]

JavaScript is so cursed.

▲user____name 5 hours ago | parent [-]

If I were to write a book on programming in JS, it would be a black cover with the JS Holy Trinity equality diagram in red, to emphasize its Satanic nature.

▲toolslive 3 hours ago | parent [-]

Satanic? never assume malice where incompetence suffices

▲hk__2 2 hours ago | parent [-]

Don’t assume either malice or incompetence when it’s just that you don’t understand the context and the reasons things are this way.

▲marcosdumay 17 minutes ago | parent [-]

The reason is that the language was designed in a week with a "product manager" pushing the developer's design into something that only has "is a programming language" in common with it during that week.

The sooner that abomination is killed, the best.

▲shevy-java an hour ago | parent | prev | next [-]

It is called ... Ruby.

(Though, parentheses are sometimes needed due to ambiguity. But by and large, the lispy legacy has been overcome already.)

▲aktenlage 6 hours ago | parent | prev [-]

What's the purpose of the +x at the end?

▲undecidabot 6 hours ago | parent | next [-]

The unary plus implicitly converts an expression to a number, which calls `valueOf` for non-primitive values.

▲aktenlage 7 minutes ago | parent [-]

Thank you

▲emaro 6 hours ago | parent | prev [-]

I think to implicitly trigger the valueOf function.

▲aktenlage 7 minutes ago | parent [-]

Thank you