Why make it complicated?
-
TypeScript doesn't need the "function" keyword for a method in an object or on a class though.
const foo = { bar(): string { ... } }
which I assume is doable because the syntax is unambiguous.
PHP's object orientation is similar to languages like Java and C#, which is what I was comparing to.
Your example didn't mention the use of the function keyword. Instead, it seemed to be questioning the placement of the return type - placing it after the argument list seems pretty common in newer languages.
-
And Kotlin.
AND MY AXE!
-
python:
a: str = 1
That's just a comment
-
Made with KolourPaint and screenshots from Kate (with the GitHub theme).
let a: &'static str
-
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?
-
You're encoding more information in the typescript one. You're saying it's a string that will get updated.
C# has const string a = "Hello, World";
var in js is legacy, and default should be let, but changing that would break everything
-
If there's only two options you only need one keyword
wrote on last edited by [email protected]True, but var and let are not same in js, so there is three.
if(true) {
var a = "dumdum"
}
console.log(a)
Is valid and functioning javascript. With let it is not.
-
So I think it's still probably unclear to people why "mix of keywords and identifiers" is bad: it means any new keyword could break backwards compatibility because someone could have already named a type the same thing as that new keyword.
This syntax puts type identifiers in the very prominent position of "generic fresh statement after semicolon or newline"
..though I've spent like 10 minutes thinking about this and now it's again not making sense to me. Isn't the very common plain "already_existing_variable = 5" also causing the same problem? We'd have to go back to cobol style "SET foo = 5" for everything to actually make it not an issue
At least in C#, you can define variables with keyword names like this:
var @struct = "abc"
I think in Kotlin you can do the same, and even include spaces with backticks like val
abstract class
= "abc"I'm not sure if other languages allow that, regardless it should be rarely used.
-
It's commonly used in math to declare variables so I assume programming languages borrowed it from there.
More specifically, they're borrowing the more mathematical meaning of variables, where if you say x equals 5, you can't later say x is 6, and where a statement like "x = x + 1" is nonsense. Using "let" means you're setting the value once and that's what it's going to remain as long as it exists, while "var" variables can be changed later. Functional languages, which are usually made by very math-y people, will often protest the way programmers use operators by saying that
=
is strictly for equality and variable assignment is:=
instead of==
and=
in most C-style languages. -
let a: &'static str
wrote on last edited by [email protected]Rust is verbose, but C++ might still take the cake with its standard library templates. Especially when using fully-qualified type names...
auto a = ::std::make_shared<::std::basic_string<char, ::std::char_traits<char>, MyAllocator<char>>>();
A reference-counted shared pointer to a string of unspecified character encoding and using a non-default memory allocator.
-
At least in C#, you can define variables with keyword names like this:
var @struct = "abc"
I think in Kotlin you can do the same, and even include spaces with backticks like val
abstract class
= "abc"I'm not sure if other languages allow that, regardless it should be rarely used.
Swift also uses backticks and Rust has a dumb one in the form of
r#thekeyword
. Still much better than introducing aasync
as a new keyword in a minor version of a language and breaking a bunch of libraries. -
Not to short-circuit the joke, but in this case, it's because the valid JavaScript version is...
let a
...and one of TypeScript's main design goals is to be a superset of JavaScript, that only adds syntax, and doesn't re-write it.
Beyond that, it's probably a case of some new language just using what the designer is familiar with.
TypeScript [...] only adds syntax, and doesn't re-write it.
I believe
enum
,const enum
, and decorators would like to have a word with you. -
I wish the interpreter cared about assignment
wrote on last edited by [email protected]Dude, even just a "FY,I, you sure about this?" would be nice. I gladly embrace python's by-all-means-shotgun-your-leg-off philosophy, but the noobs could use the help.
-
TypeScript doesn't need the "function" keyword for a method in an object or on a class though.
const foo = { bar(): string { ... } }
which I assume is doable because the syntax is unambiguous.
PHP's object orientation is similar to languages like Java and C#, which is what I was comparing to.
I believe the reason a function or method in an object does not need the “function” keyword has to do with the fact that JS is built on the prototype model and the fact that functions are first class in JS.
As the saying goes, “Everything is an object in JavaScript…” (which is not strictly true).
-
More specifically, they're borrowing the more mathematical meaning of variables, where if you say x equals 5, you can't later say x is 6, and where a statement like "x = x + 1" is nonsense. Using "let" means you're setting the value once and that's what it's going to remain as long as it exists, while "var" variables can be changed later. Functional languages, which are usually made by very math-y people, will often protest the way programmers use operators by saying that
=
is strictly for equality and variable assignment is:=
instead of==
and=
in most C-style languages.Unless you’re in JS.
-
Made with KolourPaint and screenshots from Kate (with the GitHub theme).
wrote on last edited by [email protected]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. -
Then the second part of my statement applies.
In the case of Rust, you can also omit the type annotation in the vast majority of cases and the compiler will infer it.
-
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.
Good, now invent a keyword for variables you don't want to declare the type.
auto
. Also in D, you only needconst
if you don't want to specify a type for a constant, the compiler automatically inferres it to you.Function declarations can be easily decyphered from context, no problem.
-
I think you can do
const thing = ... as const
to lock down the mutation?So is
let
in some languages. In Rust, you have to constantly opt out from immutability withlet mut
, which makes writing more procedural code feel like you're fighting with the compiler, and otherwise I don't really see the rationale behind full functional coding. I only had a bug caused only once by unwanted mutation, the hardest part fixing it was to learn the proper use of my debugger tool. -
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.