Posted by ingve 1 day ago
fn fib(n: i32) -> i32
so unnecesary, just extra writing. We're developers, we understand that function return types are after first () let mut i = 0;
No, no, copy Go here, i := 0 is just fineZig really aims to be great at things I don't imagine Rue being useful for, though. But there's lots of good stuff there.
And lots of respect to Swift as well, it and Hylo are also major inspiration for me here.
I also find that D is good between language. You can do high level or low level whenever you need it.
You can also do some inbetween systems programming in C# if you don’t care about a VM or msft.
C# Native AOT gets rid of the JIT and gives you a pretty good perf+memory profile compared to the past.
It's mostly the stigma of .NET Framework legacy systems that put people off, but modern C# projects are a breeze.
I’m looking forward to seeing how it shapes out over the next few years. Especially once they release union types.
NativeAOT's primary goal is reducing memory footprint, binary size, making "run many methods once or rarely" much faster (CLI and GUI applications, serverless functions) and also shipping to targets where JIT is not allowed or undesirable. It can also be used to ship native dynamically or statically (the latter is tricky) linked libraries.
Eventually: through not having references, thanks to mutable value semantics. Also linear types.
But that's just ideas right now. It'll get there.
Perhaps calling it an “optimization” is misleading. Certainly it makes code faster, but more importantly it’s syntax sugar to translate recursion into loops.
(To be fair, if you are programming functionally, it is essential. But to flat-out state that a language that doesn't support isn't "serious" is a bit rude, at best.)
If I put out a language that crashed after 1000 iterations of a loop, I'd welcome the rudeness.
If every iteration of a while-loop cost you a whole stack frame, then I'd be very rude about that language.
This works, btw:
#include <stdio.h>
long calc_sum(int n, long acc) {
return n == 0
? acc
: calc_sum(n-1, acc+n);
}
int main(void) {
int iters = 2000000;
printf("Sum 1...%d = %ld\n", iters, calc_sum(iters, 0));
return 0;
}Well, sure, but real programmers know how to do while loops without invoking a function call.
Yes, you can stare into the abyss, but it's staring right back"
func (lst *List[T]) Push(v T) {
if lst.tail == nil {
lst.head = &element[T]{val: v}
lst.tail = lst.head
} else {
lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next
}
}And this one doesn't even have the infamous error-checking.
Now imagine if it had semicolons, ->, ! and '.
List.add is contrived? What are you doing that's simpler the list.add?
> but that's one of the cleanest generics implementations.
You're saying it's typically worse than this?
&element[T]{val: v}
the & is a pointer, which is common across most languages, but the [T] is a dynamic type T. Otherwise it would be just &element{val: v}
He says that element[T] is a clean/simple implementation of generics.Even though I have a Perl tattoo, it'll never get like that, though.
(Semicolon rules, for now at least, will be the same as Rust)
Take this:
fn fib(n: i32) -> i32 {}
The (n: i32) can be just (n i32), because there is no benefit to adding the colon there.The -> i32 can also be just i32 because, again, the -> serves no purpose in function/method definition syntax.
So you end up with simple and clean fn fib(n i32) i32 {}
And semicolons are an ancient relic that has been passed on to new languages for 80 fucking years without any good reason. We have modern lexers/tokenizers and compilers that can handle if you don't put a stupid ; at the end of every single effing line.
Just go and count how many of these useless characters are in your codebase and imagine how many keystrokes, compilation errors and wasted time it cost you, whilst providing zero value in return.
fn fib(n i32) i32 {}
But even if they need to be written explicitly, type applications like `List a` would require syntax to disambiguate them.Personally, I would like a language that pushes the programmer to write the types as part of a doc comment.
Also think about returning lambda's. Should it look like this?
fn foo(n i32) (i32 i32) {}
Of course the IDE could help by showing the typographic arrows and other delineations, but as plaintext this is completely unreadable. > And semicolons are an ancient relic that has been passed on to new languages for 80 fucking years without any good reason.
You still have to think about stuff like currying. You either delimit the line, or you use significant white space.It should be
fn foo(n i32, m i32) (i32, i32) {}
It will also allow future implementation of named returns, like in Go: fn foo(n i32) (a i32, b i32) {}
As for semicolon, that is needed only if you have inline expression: for (;;;) {}
Or inline block, like in Go: if foo := a + b; foo > c {} > fn foo(n i32, m i32) (i32, i32) {}
But now consider returning a function with type¹ Foo<T<string, T2>> -> (bool -> IDictionary<string, T3> -> i32 -> T3) where T2 : T3
even if you leave out the latter type constraint, I think it is hard to avoid undecidable ambiguity. fn foo(n i32, m T2) (????) {}
You quickly get ambiguity due to type parameters / generics, functions as arguments, and tuples if you don't syntactically separate them.Even if you your context-depended parser can recognize it, does the user? I agree that a language designer should minimize the amount of muscle damage, but he shouldn't forget that readability is perhaps even more critical.
____
1. Note, even if the parser can recognize this, for humans the '>' is confusing unless syntax highlighting takes care of it. One time it delimits a generic type argument, the other time it is part of '->'. This is also an argument for rendering these things as ligatures.
> The -> i32 can also be just i32 because, again, the -> serves no purpose in function/method definition syntax.
Well, there is, but it's more of a personal trait than a universal truth. Some human programmers (e.g. me) tend to read and parse (and even write, to some extent) source code more accurately when there is a sprinkle of punctuation thrown in into a long chain of nothing but identifiers and subtly nested parentheses. Some, e.g. you, don't need such assistance and find it annoying and frivolous.
Unfortunately, since we don't store the source code of our programs as binary AST blobs that could be rendered in a personalized matter, but as plain text instead, we have to accept the language designer's choices. Perhaps it actually has better consequences than the alternative; perhaps not.
[2 45 78]
It’s just a nicer thing to view and type in my experience.
Regarding syntax soup, I think Odin is probably syntactically the cleanest of the lower level languages I’ve played with.
Odin seems interesting but for me it has two deal-breakers: first one use the use of ^ for pointer de/reference. Not that it does not make sense, it's just that it is not an easy key to get to on my keyboard layout and i will not be changing that. The & and * are well known characters for this purpose and, at least for me, easily accessible on the keyboard. Second issue is the need to download many gigabytes of visual studio nonsense just so i am able to compile a program. Coming from Go, this is just a non-starter. Thirdly, and this is more about the type of work i do than the language, there are/were no db drivers, no http/s stack and other things i would need for my daily work. Other than that, Odin is interesting. Though I am not sure how I would fare without OOP after so many years with inheritance OOP and encapsulated OOP.