this post was submitted on 09 Mar 2024
21 points (95.7% liked)

Programming Languages

1186 readers
1 users here now

Hello!

This is the current Lemmy equivalent of https://www.reddit.com/r/ProgrammingLanguages/.

The content and rules are the same here as they are over there. Taken directly from the /r/ProgrammingLanguages overview:

This community is dedicated to the theory, design and implementation of programming languages.

Be nice to each other. Flame wars and rants are not welcomed. Please also put some effort into your post.

This isn't the right place to ask questions such as "What language should I use for X", "what language should I learn", and "what's your favorite language". Such questions should be posted in /c/learn_programming or /c/programming.

This is the right place for posts like the following:

See /r/ProgrammingLanguages for specific examples

Related online communities

founded 1 year ago
MODERATORS
 

Call-by-push-value is an evaluation strategy that determines when arguments to functions are evaluated. Call-by-value is what every mainstream language does: arguments are evaluated before the function is called. Call-by-name substitutes arguments directly into a function, so they may be evaluated multiple times or not at all. For example, the following pseudocode:

function foo(n, m) {
    sum = 0
    for i in 1 to 4 {
        sum = n + sum
    }
    if false {
        print(m)
    }
    print(sum)
}

foo({print("1"); 2}, {print("3"); 4})

evaluated with Call-by-Value prints:

1
3
8

evaluated with Call-by-Name prints:

1
1
1
1
8

Call-by-push-value combines both by having two "kinds" of parameters: values which are evaluated immediately (call-by-value), and computations which are substituted (call-by-name). So the following code:

function foo(value n, computation m) {
    sum = 0
    for i in 1 to 4 {
        sum = n + sum
    }
    if false {
        print(m)
    }
    print(sum)
}

foo({print("1"); 2}, {print("3"); 4})

would print

1
8

The reason call-by-push-value may be useful is because both call-by-name and call-by-value have their advantages, especially with side-effects. Besides enabling programmers to write both traditional functions and custom loops/conditionals, CBPV is particularly useful for an IR to generate efficient code.

Currently, Scala has syntactic sugar for by-name parameters, and some languages like Kotlin and Swift make zero-argument closure syntax very simple (which does allow custom loops and conditionals, though it's debatable whether this is CBPV). Other languages like Rust and C have macros, which can emulate call-by-name, albeit not ideally (you have hygiene issues and duplicating syntax makes compilation slower). I don't know of any mainstream work on CBPV in the IR side.

you are viewing a single comment's thread
view the rest of the comments
[–] tatterdemalion 7 points 8 months ago (6 children)

Isn't computation equivalent to passing a function by value?

[–] armchair_progamer 8 points 8 months ago* (last edited 8 months ago) (1 children)

I believe the answer is yes, except that we’re talking about languages with currying, and those can’t represent a zero argument function without the “computation” kind (remember: all functions are Arg -> Ret, and a multi-argument function is just Arg1 -> (Arg2 -> Ret)). In the linked article, all functions are in fact “computations” (the two variants of CompType are Thunk ValType and Fun ValType CompType). The author also describes computations as “a way to add side-effects to values”, and the equivalent in an imperative language to “a value which produces side-effects when read” is either a zero-argument function (getXYZ()), or a “getter” which is just syntax sugar for a zero-argument function.

The other reason may be that it’s easier in an IR to represent computations as intrinsic types vs. zero-argument closures. Except if all functions are computations, then your “computation” type is already your closure type. So the difference is again only if you’re writing an IR for a language with currying: without CBPV you could just represent closures as things that take one argument, but CBPV permits zero-argument closures.

[–] codemonk 1 points 8 months ago* (last edited 8 months ago)

Thank you so much! For years I was carrying around the thought: Why do we have to decide between eager and lazy evaluation? Your explanations are so clear and motivate me to finally dig deeper into that topic. So approachable. Thanks!

load more comments (4 replies)