Zig: Proposal: Chaining operator

Created on 23 Jul 2020  路  4Comments  路  Source: ziglang/zig

This will be convenient syntax sugar, especially for multiply failable operations:

try (try (try thing.a()).b()).c();

becomes

thing -> try _.a() -> try _.b() -> try _.c();

I propose that we require _ somewhere in the receiver, to place the payload. More flexible that way.

As for the exact syntax, I personally like -> since it's light and clearly communicates the meaning -- however that might have problems with anyframe. Elixir has |>, Haskell has >>=, there are options.

proposal

Most helpful comment

To elaborate, what I mean by "does not work very well", is that function chaining is really neat if and only if there is a clean chain of single-argument functions that are applied in order. For example,

print(sin(cos(tan(x))));

could become

x |> tan |> cos |> sin |> print

and some people might prefer that. But if the expression is changed even slightly, such as

print(sin(1 + cos(tan(x))))

Then the function-chaining style can no longer be used and you have to go back to the ordinary expression (unless you have Haskell-style sections or are willing to create a lambda just to add 1). The same goes for when you need to include a function with more than one parameter, switch between function and method syntax, try something, access a struct member, etc.

The point is, a function chaining operator is a very specific kind of syntactic sugar that works only in very specific situations and requires even more syntactic sugar to be made more general (such as the suggested _ placeholder, which Scala has and which has been debated to death in Julia).

Overall, I feel that introducing multiple pieces of special syntax for function chaining is convenient in some cases, but goes strongly against Zig's minimalism and explicitness, not to mention the "One Way To Do It" principle.

All 4 comments

Why not have expr.try be alternative syntax to try expr? That would allow a().try.b().try.c().try.d().try, or whatever.

This proposal is both more general and less syntactically strange.

I don't think function chaining works very well in imperative languages. In Haskell it is idiomatic, but Haskell also has a lot of supporting machinery to make it more flexible (compact lambda notation, currying, sections, utility functions such as flip, etc.).

In Zig, simple method chaining can be used where applicable. Where not applicable, as in your example, I would suggest to simply be more verbose:

const x = try thing.a();
const y = try x.b();
const z = try y.c();

This has the disadvantage of introducing spurious names, but makes control flow more explicit.

Or maybe you can convince Andrew to introduce a .! operator as a shorthand for try. Then your example would be thing.a().!.b().!.c().!, though I'm not sure this is actually a good idea.

To elaborate, what I mean by "does not work very well", is that function chaining is really neat if and only if there is a clean chain of single-argument functions that are applied in order. For example,

print(sin(cos(tan(x))));

could become

x |> tan |> cos |> sin |> print

and some people might prefer that. But if the expression is changed even slightly, such as

print(sin(1 + cos(tan(x))))

Then the function-chaining style can no longer be used and you have to go back to the ordinary expression (unless you have Haskell-style sections or are willing to create a lambda just to add 1). The same goes for when you need to include a function with more than one parameter, switch between function and method syntax, try something, access a struct member, etc.

The point is, a function chaining operator is a very specific kind of syntactic sugar that works only in very specific situations and requires even more syntactic sugar to be made more general (such as the suggested _ placeholder, which Scala has and which has been debated to death in Julia).

Overall, I feel that introducing multiple pieces of special syntax for function chaining is convenient in some cases, but goes strongly against Zig's minimalism and explicitness, not to mention the "One Way To Do It" principle.

Was this page helpful?
0 / 5 - 0 ratings