Hacker News new | past | comments | ask | show | jobs | submit login

People are used to math infix operators and can use them efficiently.

But working with infix operators in other contexts would be a complete nightmare. Limiting what a given expression can "bind" to, what it can form a large expression with, is a way to limit the processing needed to understand a given piece of code. Being able to say one thing a hundred different ways isn't good if the read has to search for a hundred different maybe-meanings a given string might have.




Sometimes it's nice to be able to do piping:

  object | dothis | dothat | dosomething
I suppose the piping operator is infix. I feel like some of the advantages of the notation

  object.f()
over

  f(object)
in object oriented programming are due to this.


An interesting feature of D is Uniform Function Call Syntax (UFCS) where any function with first parameter of type T can be called as a method on T: https://dlang.org/spec/function.html#pseudo-member


That is indeed an interesting feature! I wish more languages implemented it!

In Python, of course, one argument against implementing it is that there already is the getattr magic method (and the getattribute one), so even if it'd be possible to implement UFCS without breaking changes, it would at least complicate the way attribute access works even further. But, of course, one could always introduce a new operator/token (instead of ".").


Other languages I know of that have this feature are Nim, Koka and VimScript.


I love |> in f# because of this type of thing, piping operations together instead of nesting or the like just reads so much cleaner. And yes in cases where they are all methods on the type you can have the function return self and then do value.Func1().func2().func3().etc() but only if they are methods on the class.

But I also don't care for arbitrary infix operators (which I'm pretty sure f# supports but I haven't used it in a way where I run into them). I know I'm crazy but I almost wish we did away with ALL infix operators, even stuff like +/-* and just do everything as functions. You know, like Lisp :P Edit: I guess I should clarify as it sounds back and forth. For traditional stuff everything functions, with exceptions for things like piping that are purely about chaining operations together (both |> and >> in f# are examples of infix that's specific use case is different enough from say +-/* I think they warrant it).


> but only if they are methods on the class

C# got around this by introducing extension methods. You put static methods inside any static class whose namespace you've imported and label the first parameter with `this` before the type name. Then you're able to call that static method as if it was an instance method on anything that is or implements the type of the first parameter. Basically it's an explicit version of D's unified function call syntax.

I think the pipeline operator is nicer, but extension methods aren't a bad solution.


Sure, you can fake it to get to the same place. And I've abused extension methods a lot, including on interfaces before c# made default implementations on interfaces a more acceptable thing with c#... 9 I think?


F# does allow custom infix operators, but of course prefix + piping is generally cleaner. Only time I've used custom infix are for implementing a "null coalesce" operator and for overloading math ops for vectors and matrices. The null coalescing is generally only used for code that interops with c# since f# offers non null guarantees for most types.


I can see wanting null coalesce in interop scenarios. I know I use it a lot in C#.


> I suppose the piping operator is infix.

It's more like composition isn't it?

    object | dothis | dothat
Is pretty much

    dothat(dothis(object))
If stdout is considered the return value at least.

The pipe itself is just a sort of.. notation that a postfix function follows? Whereas in mathematics the function is prefixed, and the notation itself is infix and optional. (That's a knowingly rough and lazy description that any mathematician will hate...)


I think

    dothat(dothis(object))
is more like

    < object dothis | dothat
or

    dothis object | dothat
while the full composition

    object | dothis | dothat
is more like

    dothis(dothat(object(stdin_and_everything_else)))


Yes, true! Same point I think though? I just erroneously gave `object` a different type to `dothis`/`dothat`.


Agreed!


Is it possible to do this in Python, such as:

instead of: len(my_list)

to do: my_list | len

of course you can still do: my_list.__len__() but it's ugly


> Being able to say one thing a hundred different ways isn't good if the read has to search for a hundred different maybe-meanings a given string might have.

This the absurd notion that there is some one "best" way to do things...hard core disagree.

If this were true, there should only be one library, one way of doing anything, one codebase, and therefore only one program, nay even there should only be one programmer, and Python should be a pet project of this one programmer doing everything one way...

The fact that you can obfuscate python, means python has failed its ethos in this respect (https://pypi.org/project/python-obfuscator/).

Compatibility is good, a thriving ecosystem is better.

Critically, a thriving ecosystem is made by a hundred different ways of doing something, all doing something similar, not by making everything similar, so that the first time if fails, its game over.


Yeah, relying on operator precedence makes for some of the most infuriating to read code.


Yeah, infix doesn't go well with that. Even traditional mathematical notation ends up being ambiguous because of it. However, if all infix operators are given equal precedence, it all becomes very neat. See APL (https://apl.wiki) for an example of that.


At the same time Q (which is based on apl) only allows built in functions to be infix because otherwise your code gets unreadable Especially if you also have prefix notation.

in `one two three`, are one and two functions using prefix notation or is two an infix function that takes both one ant three as arguments?

It's not too bad if you have a small amount of infix functions to remember, but I don't want to second guess everything while reading code.


Code written by people who don't know operator precedence and so put brackets around absolutely everything is significantly harder to read IME. I've seen students end up with "))))))" at the end of a line. Brackets are better as a signal that something unusual's happening.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: