- cross-posted to:
- programmerhumor@lemmy.ml
- cross-posted to:
- programmerhumor@lemmy.ml
Made with KolourPaint and screenshots from Kate (with the GitHub theme).
Good, now invent a keyword for variables you don’t want to declare the type. And now that you have a mix of keywords and identifiers on the same place, you can never update your language again.
Also, make the function declarations not use a keyword too, so you get the full C-style madness of code that changes meaning depending on what libraries you import.
I don’t understand how not using a keyword to define a function causes the meaning to change depending on imports. I’ve never run into an issue like that before. Can you give an example?
Some declarations terminate on the name, other declarations go one requiring more tokens. In C, the only thing that differentiates them is the type.
Parenthesis in particular are completely ambiguous. But asterisks and square brackets also create problems.
I have never heard of this problem for C. Can you elaborate or point to some articles?
The basic problem is that identifiers can be either types or variables, and without a keyword letting you know what kind of statement you’re dealing with, there’s no way of knowing without a complete identifier table. For example, what does this mean:
foo * bar;
If foo is a type, that is a pointer declaration. But if it’s a variable, that’s a multiplication expression. Here’s another simple one:
foo(bar);
Depending on how foo is defined, that could be a function call or a declaration of a variable bar of type foo, with some meaningless parentheses thrown in.
When you mix things together it gets even more crazy. Check this example from this article:
foo(*bar)();
Is bar a pointer to a function returning foo, or is foo a function that takes a bar and returns a function pointer?
let
andfn
keywords solve a lot of these ambiguity problems because they let the parser know what kind of statement it’s looking at, so it can know whether identifiers in certain positions refer to types or variables. That makes parsing easier to write and helps give nicer error messages.I feel this is related, and hightlight this even further, look at all the ways to initialize something in C++.
https://www.youtube.com/watch?v=7DTlWPgX6zs
If you are really lazy, have a look at making an int at around 7:20. It’s not horrible that alone, but it does show how many meanings each thing has with very little difference, added on top of years of legacy compatability accumulation. Then it further goes into detail about the auto use, and how parantheses, bracket, squiggly bracket all can be used and help with the mess.
You’re encoding more information in the typescript one. You’re saying it’s a string that will get updated.
That looks like rust ngl
It’s also valid rust syntax.
But if it were rust, this meme would not make sense, since you would just type
let a
and type inference would do its thing. Which is much more ergonomic.let a = String::from(“Hello, world!”).into()
I’ll see myself out.
At least be fair and cut out the
.into()
And bow to the compiler’s whims? I think not!
This shouldn’t compile, because .into needs the type from the left side and let needs the type from the right side.
If type constraints later in the function let the compiler infer the type, this syntax totally works.
Like if the variable is then used in a function that only takes one type? Huh.
The actual reason why let … in syntax tends to not use C-style “type var” like syntax is because it’s derived from the syntax type theory uses, and type theorists know about parameterised types. Generics, in C++ parlance, excuse my Haskell:
let foo :: Map Int String = mempty
We have an empty map, and it maps integers to Strings. We call it foo. Compare:
Map Int String foo = mempty
If nothing else, that’s just awkward to read and while it may be grammatically unambiguous (a token is a name if it sits directly in front of
=
) parser error messages are going to suck.Map<Int,String>
is also awkward but alas that’s what we’re stuck with in Rust because they reasoned that it would be cruel to put folks coming from C++ on angle bracket withdrawal. Also Rust has ML ancestry don’t get me started on their type syntax.Until now, I looked at
let
and thought, “maybe they just felt like doing it that way”.
Makes a lot more sense now.
Can we talk about PHP functions with typehints too?
public static function foo(): string {
Practically every other language with similar syntax does this instead:
public static string foo() {
Rust and TypeScript use the return-type-at-the-end convention as well.
Python too.
And Kotlin.
AND MY AXE!