News for hackers. Stuff that matters.
Re:I'm Betting on Call-by-Push-Value by charcircuit on Saturday March 09, 2024 @06:11PM (#39655408)
Imagine if functions were polymorphic over the ability to pass in a function as an argument. So both f(1) and f(() => 1) would be valid for a function that takes a number. It would also apply to variables and such too. So "const a = () => 1; const b = a + a;" would be possible to do.
Re:I'm Betting on Call-by-Push-Value by rezonant on Saturday March 09, 2024 @06:35PM (#39655505)
This is a good explanation. So effectively it's making the lazy/eager distinction controlled by the caller and not the callee.
Re:I'm Betting on Call-by-Push-Value by Izkata on Sunday March 10, 2024 @12:15AM (#39656883)
Ahh k. So like Rebol and Red have worked for decades:

  >> F: func [A][print type? :A   print join "Arg: " A]
  >> F "Foo"                                           
  string
  Arg: Foo
  >> F func [][return "Bar"]                           
  function
  Arg: Bar
I really got spoiled learning Rebol as my first language, I'd already internalized a ton of concepts long before they were introduced during school and college. Higher-order functions were the first time I really realized it, I guess here's another to add to the pile.

Even knowing this though, that post really is really obtuse. Definitely could have been better written.

Basically in these languages, functions don't have a special syntax to be called, like F(), they just get called when used. So usage of a no-argument function is identical to a variable, and what happens depends on its datatype (function, string, whatever). The special :A syntax is to get the value without evaluating it if it is a function.

Re:I'm Betting on Call-by-Push-Value by vidarh on Sunday March 10, 2024 @11:19AM (#39659841)
That's already the case for any dynamic languages, and it's just down to whether you write your code to be flexible about inputs. E.g

    def int(i) = i.respond_to(:call) ? i.call : i.to_i

    def f(i) = int(i) * 2
f in this case can take both ints and lambdas or anything call-able.

In practice we'd usually do this via any of the normal conversion methods like expecting the caller to support to_i etc., and bear the complexity for us as needed unless there's a really compelling reason to think the caller will often want to defer the evaluation past the call site and into the method itself.

That's usually very obvious when you come across it, like e.g. if the argument is expected to come from a remote source, but as long as the API for how the method uses the value is clear, substituting the value for a deferred calculation is easy.