4 ms·
I much prefer languages which simply do not make a distinction between functions and operators. This distinction seems useful only in the context of lower-leve
by abjKT26nO8 7y ago
I much prefer languages which simply do not make a distinction between functions and operators.
This distinction seems useful only in the context of lower-level languages like C where the operators translate directly to single machine code instructions and thus they provide clues about performance.
But in a higher-level language this distinction is superficial. It's just another function, just with a much shorter name and perhaps using infix instead of prefix notation. E.g. in Lisps there is no such distinction. "+" is a valid function name. In Haskell - same, but you also have a built-in syntax for specifying that you want your function to be called using infix notation by default.
- bambataa 7y agoIn principle I agree with this. But as a relative beginner to Haskell operators and their precedence levels are a barrier. Operators/functions like `+` have well-understood semantics but I don't see how anyone could have an intuition for what `.:` does. On precedence, I find myself wishing my editor could show me the expression fully parenthesised so I can see if I'm not mentally parsing it correctly.
- gowld 7y agoIf we teach operators to children they won't become adults biased against some operators they haven't learned.
- AnimalMuppet 7y agoSee Silhouette's post that is parallel to the parent. These operators don't make sense until you know the underlying concepts. Teaching the whole thing to children seems ambitious enough to probably be unrealistic.
- Silhouette 7y agoOperators/functions like `+` have well-understood semantics but I don't see how anyone could have an intuition for what `.:` does. As with many concepts in programming, or any other field that has its own language for that matter, a lot of this comes down to experience. If you're used to OO-friendly languages like Java or Python, you probably think of the operator (.) as looking up a field or method on an object. If you're used to FP-friendly languages like Haskell, you probably think of (.) as function composition, and it's just as familiar and everyday a sight. To someone who is new to Haskell or broader functional programming concepts, it might not be immediately clear why ($) is useful if you already have (.), but it's something you soon use as second nature. Before long, you come across concepts like Functor, Applicable and Monad, and with them operators like (<$>), (< * >) and (>>=). The behaviours those operators represent don't even exist outside the context of the underlying abstractions, so someone who isn't familiar with the abstractions won't understand what those operators mean or why they are useful. Again, though, in Haskell these things are routine, everyday tools, just like using (++) to increment a variable in a language like C or JavaScript. That increment operation makes little sense in a functional language where mutability is not the default, and Haskell has no direct equivalent and indeed uses (++) to mean something completely different. By the same token, to someone who uses (.) all the time for composition of two unary functions, using (.:) for composition of a unary and a binary function is only a small mental jump and makes sense. None of this is to say you can't take things too far, but it's important to distinguish between using unnecessarily cryptic notations for no good reason (usually a bad idea) and using notations that might appear cryptic to someone who doesn't yet know the concepts but that provide a concise notation for something that is used all the time by someone who does (often a good thing).
- Aardwolf 7y agoHow do you deal with namespaces (or anything analogous like package names) there? E.g. if you have a function named "+", it can likely clash with other functions named "+" If the programming language supports function overloading that can be resolved through the types By the way, I actually like RPN calculators, and low level stack based programming languages, where operators and functions also work the same way, but that is mostly interactive or for small self contained programs
- abjKT26nO8 7y agoThis is a problem of the model of polymorphism a language has. It's orthogonal to the function/operator distinction. It doesn't arise based on having this distinction or not. In Haskell you use typeclasses (you can think of them as Go interfaces or Rust traits) and without them you cannot introduce nameclashes. In Scheme (the Lisp that I know)... you don't have anything. You import things from libraries, define variable bindings and depending on the order of all this your variable is going to be bound to something, most likely a procedure... but which one? Depends on the order. Not great. I prefer the Haskell approach to this, but then Haskell is a bit complicated in other areas. :/ But again, this has little to do with "operators vs functions".
- Aardwolf 7y ago> But again, this has little to do with "operators vs functions". It has to do with it in the sense that you can add package names or namespaces to function names which are already text, but it looks bad to do this with symbolic infix operators like "+" It would be nice if everything that operates looks exactly the same, but maybe the field of mathematics could start with fixing their notation then instead: mathematics uses a bit of everything you can imagine: add, subtract, multiply, division, power, root and log are all binary operators and instead of making them all look the same, mathematicians have chosen to: * infix symbol for add and subtract * no symbol at all (usually) for multiply * superscript for power * horizontal bar and put things on top of each other for division * another horizontal bar and a superscript on the left for root * function-name notation with subscript for log Maybe this is a global optimum that math has converged to because this mix of different things actually is the easiest way for the human brain to read formulas the fastest, e.g. the arbitrary grouping that division creates and the fact that this eliminates the need for some parenthesis, and the easy visual difference between all the different notations, may really help. In some programming languages, if you've got dozens of parenthesis or deeply nested indentation, can you easily tell which argument is to which function? Or, it's just a historically grown monster that could as well have turned out entirely different and can have other forms that would be faster to interpret.
- hansvm 7y agoIt's mostly true that operators are equivalent to functions, but there's an important distinction at parse time too for most languages. You can have functions named foo, bar, and foobar, but without some sort of convention (usually whitespace or other delimiters) it isn't possible to look at the string foobar and identify whether this is supposed to refer to the single function by that name or to whatever having foo and bar adjacent means in your language (probably composition or application). Contrast that with operators like +, which serve as delimiters by themselves and can be unambiguously placed next to other function names because they're drawn from a different character set. Whether that convenience is worthwhile is up for debate, but I think it would be surprising to type a+b and get some kind of parse error that can be rectified just by typing a + b instead.
- clarry 7y ago> Whether that convenience is worthwhile is up for debate, but I think it would be surprising to type a+b and get some kind of parse error that can be rectified just by typing a + b instead. I kinda prefer that a+b lexes as one identifier: a+b. Also rabbits-are-cute.
- XuMiao 7y agoExactly. a+b should be the same as a.add.b A high level programming language should be designed for communication instead of dictating the computations.