4 ms·
What's with newer languages putting types after variable/function names? Then you need an extra symbol : or -> and a function keyword. It also breaks readabilit
by blakerandall 4y ago
What's with newer languages putting types after variable/function names? Then you need an extra symbol : or -> and a function keyword. It also breaks readability of long function headers as you have to read the name skip to the end to read the return type then back to the first argument. Is there a good reason for this trend?
- teo_zero 4y agoIf you had never heard about C and its legacy, and were to create your own programming language, would you come up with a syntax like C's? The structure 'term: definition' is pretty common in many natural languages and has a lot of advantages: all terms are aligned, you can sort them, you can grep the term you're looking for, etc. I even think it should be extended to functions, too. That 'def' ruins the harmony. Instead of def factorial(int) -> int it should be factorial: fn(int) -> int You trade a keyword ('def') for another ('fn') but open the way to lambdas (just the part after the colon). I agree that the -> serves no purpose, it could be made optional. Alternatively one could require the -> and dismiss the 'fn' keyword, like this: factorial: (int) -> int It's slightly harder for the parser who has to wait until the -> to understand what it's reading, but it's doable. About putting the return type after the parameters, that absolutely reflects how I reason about functions: I will want to first examine its input, and then its output. Even the man pages for common functions and commands explain the parameters first, and leave the return value last.
- JaDogg 4y agoI think mainly 1) Easy to parse (less ambiguous) 2) We like Python
- Yujf 4y agoIt is easier to parse and you don't get the abomination that is C function pointers
- MathMonkeyMan 4y agoIt makes me wonder why C put the ultimate type on the left and not on the right. C type/variable declarations are an expression that transforms the type/variable into a primitive type, which is then annotated on the left of the expression. Why not on the right?
- jstimpfle 4y agoBecause parsers, like humans, read from left to right. Important parsing decisions are usually made as early as possible. An example is recursive descent parsing, which derives its simplicity from making decisions first, allowing a top-down parse. And when humans skim text, I bet it can be shown that it's easier if the syntactically significant locations are aligned near the beginning of each statement.
- jejones3141 4y agoThe intent, as I understand it, is that "declaration should look like use", so that the base type is on the left. If you declare int *foo; then *foo is an int. IMHO the existence of "cdecl" is evidence that it might not have been the right choice.
- imtringued 4y agoDeclaration should look like use is nonsense though. I mean, what is the practical benefit of putting the pointer to the left of the name instead right to the type? For pointers the difference is literally just on which side of the space the asterisk sits at the expensive of making it unreasonably difficult to represent nesting of type constructs.
- UncleEntity 4y agoIt’s super easy to parse, I added types to a JavaScript parser I play around with in maybe a half an hour just to see if I liked it. It probably helped that I just parse to an AST that’s generated so experiments like this are trivial.
- jounker 4y agoIt’s super easy to parse until you have interesting higher order functions.
- zumu 4y agoVariable/Parameter names are nicely aligned so there's less scanning to read them. Personally I usually read function arguments before return type, but I can see instances where I'd want to look at return type first. If you're line breaking on parameters for long function signatures, it's not so bad though—the return type will be in a predictable place.
- zokier 4y agoThe convention dates back to at least ML in the 70s, possibly even longer time back. So it is not some new thing, it's recent rise in popularity is more a reflection in MLs increasing influence in language design space. If I'd had to guess, the syntax might be inspired by math notation such as x ∈ ℝ
- mikebenfield 4y agoWell, note that partly due to the way variables and functions are declared in C and C++, parsing those languages (especially C++) is a complete mess. I think the readability argument is pretty subjective. Personally I find declarations in for instance Rust a lot easier to quickly scan than C++. For one thing the names of functions are all at the same offset, which to me is actually the most important thing. I can see at a glance whether it's a function or variable being declared. I've never found the fact that the return type is at the end to be a problem - why would it be? fn first_function(...) -> i32 { ... } fn second_function(...) -> Vec<i32> { ... } const X: i32 = 0; vs int first_function(...) { ... } vector<int> second_function(...) { ... } int X = 0;
- waselighis 4y agoI think the C syntax was actually a compromise to simplify the grammar. Remember C dates back to the 60s, and computers had very little RAM and storage back then, so they had to be very clever in how they designed the language. The C function pointer syntax is the way it is because you can reuse the same grammatical rules for parsing types as you do expressions. Pointers are prefix and function calls are suffix.
- sideeffffect 4y agoIt's been like this in the academia (Mathematics in particular) since ever. Also, some people say that it makes for easier (less ambiguous?) parsing. But the -> part is a bit weird. It "shouldn't" be def factorial(x: int) -> int: but it "should" be def factorial(x: int): int = Maybe it's that way because of Python?
- JaDogg 4y agoyes
- atombender 4y agoSome languages use the colon syntax, such as the Pascal family. Others, like Rust and Gleam, use the arrow syntax. The arrow syntax meshes better with the idea that there's a difference between the types of values, and the meaning of a function signature. "foo: t" declares a name "foo" as having a type "t", but functions are abstractions — what is the "type" of factorial()? It's not "int". The type of factorial() could be written: (int) -> int or just: int -> int If you look at the ML family as well as Haskell, that's exactly how they express it. They do that for other reasons, too; those languages follow lambda calculus, which only has single-argument functions, so all functions are simply mappings between a single value to another value.
- unrealhoang 4y agoBecause type before name is simply worse in every metrics, hard to parse, hard to omit when infer (change to auto, var, etc), hard to grep for definition (hence the hack <type>\n<name>). Why do you care about the return type before the name?
- mostlylurks 4y agoThe : and -> are not strictly speaking necessary. Some languages, like go, put the type after the variable name and return type at the end of the function signature without requiring a : or a ->.
- xigoi 4y agoHaving to always use a colon before the type is better than having to sometimes write "typename" before the type. Not to mention that it makes the code easier to read.