Hacker News new | ask | show | jobs
by wisnoskij 1327 days ago
I feel like they are making languages too complicated. Most projects should just be garbage collected, most don't need to deal with pointers or anything advanced. We need variables, functions, conditionals, loops, exception handling, struts, and a library with a bunch of standard utilities (including simple I/O and string managment). Everything else should be optional and kept out of sight unless you are looking for it IMHO.

I am probably just old and set in my ways, but I have been learning rust over the last few days, and it is really syntax dense. Their is no reason it needs to be this complex. For example I think "String" and "&static' str" are different types, and no one explains what "&static'" is but I dont think it is changeable. It is not like ' or static means anything and can change, it is just basically random syntax you have to memorize. OK, I am sure it means something like a reference to a static character or something, if you dont even think it is a good idea to inform people what it means, dont implement the syntax like that.

8 comments

I will agree with you that most languages should just be gc. Rust is niche; targeted at applications where you need control over memory and layout. It is not a good general purpose language.

That being said, most of things you pointed out as “no reason to be this complex” do have good reasons. String and &str could be renamed to StringBuf and StringSlice. The String type lets you manipulate the string value, but it is a bigger type than a slice (&str). &’static just indicates that the string slice will live for the entire program. As you continue to learn Rust, more of these distinctions will make sense to you.

GAT’s themselves are actually a great example of a feature that adds capabilities without really adding complexity. They feel like they should have always been there, and I feel like anyone who has worked with the language for a while has implicitly tried to do this and was surprised it didn’t work.

> I feel like anyone who has worked with the language for a while has implicitly tried to do this and was surprised it didn’t work.

Just to lend some extra evidence to your assertion, I hit the lack of GATs within two days of starting to learn Rust. In the natural course of trying to solve a problem, I tried to write `LendingInterator`, and discovered that I could not.

Agreed, people should not assume that the design of Rust is some sort of statement about how higher-level languages should operate. It's a very targeted design with specific goals. For instance, the fact that Rust eschews exceptions should not be interpreted as "exceptions are bad", but rather "we don't think exceptions are a fit for what we're trying to achieve in this one specific domain".
String was indeed once named StrBuf: https://github.com/rust-lang/rfcs/pull/60
> without really adding complexity

Pretty sure many relevant contributors have said it is the most complex language feature since async ..

certainly complex from a implementation standpoint, and some of the rough edges can be a footgun around lifetimes until those are ironed out. But being able to add generic arguments to associated types is just a natural extension of the language from a user standpoint. You could already add generic arguments to functions, structs, type aliases, enums, etc. This just allows it in one more place.
Most things don’t need to be written in Rust. But C/C++ exist for a reason, and Rust for effectively the same reasons.

Rust looks complicated but it’s a complicated problem that’s why the solution is complicated.

If you want zero cost (e.g no GC!) abstractions and some compile time guarantees about concurrency and memory safety well then you have a complex problem requiring a complex solution.

&str is a “slice” of a string, it doesn’t own any characters it just points to someone else’s characters. String is a heap allocated string so it has its own characters.

The ‘ indicates a lifetime and “static” just means “lives forever”.

In the end, lifetimes and multiple string types is the price we pay for performance and safety. There is no world where Rust just had ergonomic strings like Java and safety/performance unaffected.

`&'static str` is an `&str` (string slice) with a `'static` lifetime (ie. lasting the duration of the program). It is most commonly encountered with string literals.

In some languages, it is appropriate to gloss over the differences between `String`, `&str`, and `&'static str`, but in Rust, all of those details are meaningful and important. If distinguishing between them isn't important to you, there are other languages that probably better reflect your needs.

> I feel like they are making languages too complicated.

Perhaps. But this topic is not a natural springboard for that topic since GATs are about lifting a current restriction in Rust. So you have the same features as yesterday, but with one less (arbitrary-looking) restriction.

Maybe it makes the language more complicated to implement (?) but it doesn’t make it more complicated for the language user.

`&` and `'` do mean something: `&` indicates something that's borrowed, and `'` indicates a lifetime. (`static` is a specifically blessed identifier given to a certain lifetime.) This is explained in https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#..., and the static lifetime is explained in https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#... .
It's also possible to have `&str`s with smaller lifetimes than `'static`, in which case you will have a different lifetime specifier there.
Ah, so this probably tells the compiler where to insert the free? If I gave it a local lifetime it would free the memory on function return for example, even if I tried to return a reference to it? Basically Rust just forces you to code in the memory freeing at the definition state of variable creation?
Not quite. Lifetime annotations prevent you from accidentally using references after the value they refer to has been freed. They track how long things will live, instead of defining how long they will live.

Basically they turn use-after-free errors into compile errors.

(I'm using 'free' here to mean cleaned up in general. Lifetimes can track stack values.)

It looks like I will just have to bite the bullet and actually read the rust book back to front. I find static particularly confusing because of the seemingly contradictory meanings that are all jumbled up in my head. The English meaning of immutable, the Java meaning of instance agnostic, and this Rust meaning of immortal lifetime.
> It looks like I will just have to bite the bullet and actually read the rust book back to front.

I mean, there you have it, right? Not a diss on you specifically, but I've often noticed that some people will complain about something, but then it comes out that they actually haven't learned it deeply enough, they're just going on what they either learned so far, learned that something in a haphazard way, or didn't learn it at all.

I used to do the same, so no shame, starting off writing programs as practice and googling things along the way because everyone on any programming thread says "the best way to learn is by building, not doing tutorials" but that's not necessarily true. Sure, I have learned a lot by building, but I've often spent longer simply running around googling and learning bits and pieces than the time I'd spend actually learning something top to bottom, front to back, from scratch. So I actually like and see the value of tutorials now.

Once I read The Rust Book front to back like you said, I understood a lot more of the language than my previous attempts to learn it a few years ago. Doing Rustlings at the same time was great too.

Garbage Collection is extremely complicated. It is a whole other program running to manage your memory using extremely complex, hyper optimized algorithms that have lots of best and worst case scenarios depending on which one you use.

GC implementations can very easily make code confusing. Consider `finalize` in Java - a destructor that gets called at a completely indeterminate period of time, making it a very confusing tool for resource management.

I find Rust trivial by comparison. But isn't that interesting, how we all view simplicity so differently?

That is why finalize is deprecated for removal, and will eventually be dropped from Java.

https://openjdk.org/jeps/421

One is supposed to use try-with-resources, determinist resource management, or cleaner types.

I did want to say Rust was complicated, I meant to say it was complicated to learn. You never need to learn the Java syntax finalize, it is invisible until you have a problem where that is the solution. Similar to Java templates or overloading they dont exist until they are the solution to a problem you are having.

My critique is that Rust appears (and I am probably wrong) to have a problem where syntax for complicated language features appear in the simplest code that even a day 1 grade 8 student needs to memorize, even if they wont understand it until the second year of university.

> syntax for complicated language features appear in the simplest code

IDK, I hear you but I'm of two minds.

1. I think a lot of this is familiarity.

`public static void main(string[] args)`

That's a lot of stuff that I don't actually really need to care about but is in every single Java program. It even has 'static', which is honestly something I found very very confusing when I first learned Java (technically my first language since I took a course at a local community college).

Compare that to c, `int main()`

That's a lot less in my face for sure.

But if I were used to Python? I'd just write my code directly in the file and it would execute from top to bottom. WTF is this `int` and `main` ???

In Java you have int and Integer, and Integer can be this "null" thing? I just wanted to add 2 and 2 wtf??

Generics? `class Foo<T>` ? WTF is `<>`?

The point is that what you have to learn when you first use the language is really going to depend on what you learned before it. I don't consider that complexity, it's just new.

The thing is that there is no language that you're likely to have used before that will prepare you for some bits of Rust.

2. Rust could be easier. It would be cool if there were a way for beginners to think less about the differences between String and &'a str and &'static str. At the same time, abstracting over those would have its own downsides - if you learn about strings in Rust in a way that abstracts that all out, will you understand the underlying components and how the abstraction works? It's tough.

I think the reality is that Rust is just not going to be as easy to learn as the same exact language but where lifetimes are managed at runtime. It probably shouldn't even try too hard to be that easy, because being that easy has costs, and there's a limit to how much you should optimize for newcomers. Rust has balanced things pretty well so far there - 2018 brought a lot of ergonomics wins that I frankly don't care for very much or even just forget about, but it helped tons of people pick the language up.

All this is to say, I think there's truth to what you're saying but I also think you may be attributing some issues to complexity where I believe it's an issue of familiarity.

I appreciate your opinion on this though, I do always find it so interesting to hear about how others view complexity and programming languages (when they're constructive about it).

Highly agree with #1. I think it really does come down to familiarity. I've learned all the languages you listed and every time there was something that was confusing only to then be cleared up the more I use it.
Explicit knowledge if variable is copy/clone or reference is useful also in GC context if the variable is mutable.
I think that if you feel like that, you might be looking into the wrong language. Go sounds like an exact match of what you want.