Killing `Ok(())` with `ok!()`

Of course. But note that I wrote "I disagree" and not "You're wrong". I did not try to invalidate your experience in any way, I just expressed my own, which is contrary to yours.

4 Likes

I still believe we should have gone with method-like postfix .await() but that's not important right now! Also off-topic!

I actually thought of suggesting this when I posted my sample function. It generalizes better than anything else short of try blocks with auto-wrapping, but if we do get those (as suggested above by @newpavlov), is there any remaining case where we'd still want .wrap(Constructor)?

(The name of any postfix wrapping method has to be totally new; it is abstractly a map operation but we can't call it .map because that already means something else for so many existing types.)

this "wrap" method is actually a function pipelineing operator (usually written |>) in disguise.

this operator is becoming increasingly popular in various languages, existing in Unison, and being proposed for both javascript and nix.

7 Likes

A generalized version of this was already proposed, the proposed syntax is x.(f)(*) as syntactic sugar for f(x, *).

(Maybe I will update the post with the link for the proposal later.)

6 Likes

I think the actual solution to "I want a free function in a chain of operations" would be to have a pipe composition operator.

Is it? map, to me, is about changing what's "in the box" (in monad speak) while this is changing (adding) the box itself. Haskell calls this return which is…taken. wrap certainly feels better to me.

2 Likes

So would this look like some_value.(Ok) or some_value.(Ok)()?

As promised, here is the link for the proposal:

Regarding the question:

If I'm not mistaken, val.(Ok) creates a closure equivalent to || Ok(val). To actually execute the function and get Ok(val), we need the trailing parentheses:val.(Ok)().

1 Like

I don't see why we should settle for this weird syntax instead of the pipelining operator |>, which looks much nicer:

something.(func)(args)
// vs
something |> func(args)

By the way, there is already a well-known crate for this, tap. With its pipe method, the above becomes

something.pipe(|x| func(x, args))

To wrap something in Ok, it is just

something.pipe(Ok)
4 Likes

I kind of like pipelining as a general concept (even if I have very little use for it) but it doesn't seem to "kill Ok(())".

Compare:

Ok(())

().(Ok)()

() |> Ok

().pipe(Ok)

Syntactic differences aside, they are all more or less equivalent noise.

The thread mostly steered away from "killing Ok(())", the pipeline was brought up for Ok-wrapping long chained expressions, not ().

1 Like

The downside of dedicated pipe-forward syntax like that is it’s not obvious where the input goes in the argument list. Nowhere else in Rust do we have argument lists that omit arguments that aren’t self.

Now of course you can say this is just one more piece of syntax to learn, which is true. We’d definitely get used to it, the way people get used to the method/function duality. But in a language without implicit currying, it’s not just another binary operator, at the very least.

3 Likes

I think the idea for proposing the syntax x.(f)(*) rather than x |> f(*) is from the observation that . is already a pipe operator, but one that works only on functions that we call "methods", and the idea is to naturally extend the existing operator rather than introducing a new one.

Furthermore, the . operator is arguably preferable, since it is more visually consistent. Consider the following:

x.method1(*)
 .method2(*)
 .(function)(*)
 .method3(*)

Chaining like this will look much less natural if you replace .(function)(*) with .(function(*)) and especially with |> function(*).

But regardless, I think that an agreement on whether some kind of pipe operator should be added is more important than argument about syntax.

Maybe this conversation should be split into its own thread, with Ok-wrapping as one motivating use case?

4 Likes

It's the map for the identity functor. But I agree that calling it map can be confusing for people thinking more in kinds of boxes or containers.