6 ms·
The argument you make about literature is one I have made before, but I don't think it applies here. To me, languages with clean syntax aren't just removing thi
by bmitc 2y ago
The argument you make about literature is one I have made before, but I don't think it applies here. To me, languages with clean syntax aren't just removing things arbitrarily. They remove things that aren't needed or they otherwise have large amounts of consistency.
Let's look at three implementations of a doubling function in modern languages where at least two of them are considered "clean" syntaxes.
F#:
let double x =
2 * x
Python:
def double(x: int) -> int:
return 2 * x
Rust:
fn double(x: i32) -> i32 {
return 2 * x;
}
Tying back to my original point, are the brackets, annotations, semicolons, and return really needed? From my perspective, the answer is no. These are the simplest functions you can have as well. The differences get multiplied over a large codebase.
Are people here really making the argument that F# and MLs don't have clean syntax? All three of these functions have the same IDE behavior in terms of types being showcased in the IDE and also in the type-checking processes, with F# and Rust's type-checking happening at the compiler level and Python's happening with MyPy. People might argue that I left off type annotations for F#, and that's true, but I did so because they aren't required for F# to compile and have the same IDE features like the other languages. Even if I did, it would look like:
F# with type annotations:
let double (x: int) : int =
2 * x
which is still cleaner.
- steveklabnik 2y agoIdiomatic Rust would look like this: fn double(x: i32) -> i32 { 2 * x } The reason Rust requires types here is because global inference is computationally expensive and causes spooky action at a distance. The only real difference between your F# and this is the braces, which I do personally think makes code easier to read. Of course there’s more overhead in smaller functions. I’d never write this code in Rust. I’d either inline it, or use a closure, which does allow for inference, and dropping the braces given that this is a one liner: |x| 2 * x Different needs for different things.
- itishappy 2y ago# Rust let double = |x| 2 * x; double(3); // F# let double = (*) 2 double 3 -- Haskell let double = (*2) double 3 # Python double = lambda x: 2 * x double(3)
- bmitc 2y agoIf I am understanding that |x| 2 * x in Rust is an anonymous function, another F# equivalent is fun x -> 2 * x.
- neonsunset 2y agoThe Haskell and F# examples above use partial application. This also works: let zeroCount = numbers |> Seq.filter ((=) 0) |> Seq.length
- steveklabnik 2y agoIt's a closure, not just an anonymous function, though it of course has an empty environment so it's not a significant difference in this case. Rust doesn't have syntax for anonymous functions, only closures.
- deleted 2y ago[deleted]
- bmitc 2y agoI thought that the Rust playground was requiring me to use return, but I was mistaken. However, it actually lends to my original point though because I would wager that dropping the return was part of the influence of ML on the beginnings of Rust.
- steveklabnik 2y agoExpression orientation certainly comes from that general space, for sure.
- IshKebab 2y ago> Tying back to my original point, are the brackets, annotations, semicolons, and return really needed? From my perspective, the answer is no. These are the simplest functions you can have as well. The differences get multiplied over a large codebase. The answer is no for this trivial function. As your code goes beyond this it gets harder for humans to parse and so the syntax becomes more necessary. My earlier analogy is pretty perfect here actually. Do you really need spaces in "thank you"? No clearly not. Does that mean you shouldn't use spaces at all? > Are people here really making the argument that F# and MLs don't have clean syntax? No. You are literally replying to a comment where I agreed that it is "clean".