It's true. Ever since I got familiar with the ownership concept, I've taken to writing C# IDisposables with disposable member variables like this:
public MyObject(){
this.myResource = new DisposableResource();
this.ownsMyResource = true;
}
public MyObject(DisposableResource resourceToUseThatIDontOwn){
this.myResource = resourceToUseThatIDontOwn;
this.ownsMyResource = false;
}
public void Dispose(){
//not pictured: .NET's boilerplate dispose code
if(ownsMyResource) myResource.Dispose();
}
For the client I'm contracting with right now, mismanagement of disposable resources is the #1 issue in the codebase. 100k lines of code, and it's never clear who should be disposing connections. There are some objects with multiple constructors (like above) that have 'conditional' ownership. In Rust, it's impossible to have this problem, period...although the above C# construct simulates it, lol.>The drop flags are tracked on the stack and no longer stashed in types that implement drop.
But just as a counter-argument, look how a simple lock looks like in Rust [1]:
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
//...
}
[1] https://doc.rust-lang.org/book/second-edition/ch16-03-shared...----- edit: Just to clarify my point. The ownership model is a beautiful solution to the resource management problem. And as the parent pointed out, some concepts can be cleanly borrowed/reused in other languages.
But now, in Rust, in practice, you realize that this model requires a lot of boilerplate code just to make the borrow checker happy, even for simple things like using a lock: create Arc(Mutex(data)); clone the arc reference; move the new Arc reference to the new thread.
extern crate crossbeam;
use std::sync::Mutex;
fn main() {
let counter = Mutex::new(0);
crossbeam::scope(|scope| for _ in 0..10 {
scope.spawn(|| *counter.lock().unwrap() += 1);
});
println!("{:?}", counter);
}
Four lines to declare a mutex, start 10 threads that all lock that mutex, increase value behind mutex, unlock mutex, and join all spawned threads. There is a lot going on here (unwrap is arguably a noise here however, but the rest is straight to the point).Also, it's possible to use atomic ints here instead of mutex. Verbosity of mutex actually helps a bit, because locking is fairly expensive and it's better to avoid locking if possible.
Something like
withLock(counter, (num) => {
return num + 1;
});
or in alternative, withLock(counter, (ref num) => {
num++;
});
If C# allowed for trailing lambdas it could look better.Yes it can be a pain to write. But I prefer the pain of making the compiler happy than the pain of debugging a weird segfault.
[0]: https://dlang.org/
* compiled, statically-typed, GC'd
* _very_ fast compilation (this is DMD; haven't tried the other two implementations (one on LLVM, the other on GCC))
* very fast executables
* easy linking with and use of C libraries
* familiar and practical
> And I don't need that last drop of performance either.
You probably write more highlevel code? Rust is --as the name implies-- most suited for close-to-the-metal code. This is often where that "last drop of performance" counts.
There are a lot of projects that really could be written in a high-level language, but they were started when C was still preferable due to the immaturity of higher-level solutions. I think it is sad that people, looking at these aging and unaudited C codebases, are thinking about rewriting them in Rust, when rewriting them in e.g. Python might make better sense. Very little Free Software needs to be so close to the metal, and it was just a historical accident that we got so much written in C.
So the historical accident was UNIX/POSIX taking over the majority of OS architectures.
I agree... apart from the Python bit. :) When deving software that is very big (LOC) or very widely distributed (FLOSS packages), then I prefer "well typed" languages that do not need a VM/interpreter.
My personal answer to that is OCaml. The only thing I miss there is good concurrency support. I can see how this might open a whole new can of worms. Would we still use locks, or some addition to the type system like Pony's reference capabilities?
I wish there was a higher level Rust sublanguage where heap allocation and GC was default, and you would use the "bare" Rust for the fast core of your program.
I'd like to see a language that is both systems and high level at the same time, with trivial interop and a common build system + package manager.
This could e.g be a set of low level extensions added to C# (Span<T>, ref returns etc is getting there) or a high level wrapper language/subset for e.g. Rust.
There is always a best tool for the job, and most jobs might require two tools, so it would be great if those two tools were aware of each other and came in the same toolbox.
The two most mature, well-designed languages in the Rust world are Gluon [1] and Dyon [2]
I believe there is a _great_ opportunity for something like Terra [3] but woven into Rust. Perhaps with the same type of compiler plugin that enabled HolyJIT [4]
The grail is having both a GC and an ownership based gc-free lower level all in the same language. Start dynamic, harden to static and sprinkle in properties.
As a side note, I have been thinking about how to bolt ownership onto a dynamic language and then I learned about Snowflake [5]. I think it would be totally doable to bolt ownership onto Java using annotations and AoT subsets of a program, completely escaping the garbage collector. This would be like Terra++
[1] https://github.com/gluon-lang/gluon
[2] https://github.com/PistonDevelopers/dyon
[4] https://github.com/nbp/holyjit
[5] https://www.microsoft.com/en-us/research/publication/project...
The core language "just works" pretty pleasantly on other *nixes, I don't know about windows.
You end up missing Apple-specific libraries a lot, though. There are some packages making progress on that problem, but a comprehensive replacement for e.g. audio or graphics surfaces is a ways off, I think, if only because of the fragmentation that exists in those spaces on other platforms. Of course, Swift has that problem only a little worse than any other language that ships without an OS.
On Linux there is official support for Swift.
The "core language" pretty much works great on Ubuttnu, but there are still minor annoyances getting it installed, or building it, on Linux. Other Linux targets, also doable, but more annoying. Windows, I haven't really heard of people doing for real. Not sure that's even on anybody's radar.
What's really awesome is how far Swift has come with the core lib Foundation, which is a from-scratch clone of Apple's Objective-C and closed-source macOS/iOS Foundation library[1], written in Swift, in the open. It is not done, but huge swaths of it are now done[2], and that makes coding in Swift on Linux a lot more pleasant, since we don't typically want to waste time rolling our own regex support, Unicode string manipulations, basic geometry routines, HTTP networking, date formatting, etc. But Foundation is a huge, almost 30-year-old library that has evolved continuously and has shipped with every OS X/macOS/iOS release. An open-source Swift re-implementation of that sounded like "yeah right" bullshit/fantasy when they announced it but now it looks very real just a couple years later.
Tooling is different issue, though. Swift is a modern language with excellent support for auto-completion and in-editor hinting and help. People complain about it all the time, but Xcode is so much better than any IDE on Linux (or any other platform) for coding in Swift that I do most of my Swift-on-Linux work using a Mac, with Ubuttnu running in VMWare Fusion. If a basic editor will do, though, you have a lot of choices. For builds and package management, Swift Package Manager is now built into Swift, and works great. (It also has an option to automatically generate Xcode project files from Swift packages, which is hugely useful; my practice, and I think the prevailing or at least emerging convention, is to keep the package and source in git but treat the Xcode project as a throwaway item, not in version control, that can be generated whenever needed. So you don't need Xcode, but its easy to use for editing convenience when you want, assuming you have a Mac. But not all devs need to have Macs.)
I think you still have to like Swift a lot to choose it for your Linux project, but it is doable. I'd be surprised if Swift adoption on Linux didn't quintuple or sextuple by the end of 2018.
[1]: https://github.com/apple/swift-corelibs-foundation
[2]: https://github.com/apple/swift-corelibs-foundation/blob/mast...
One of the reasons iOS is more smooth than Android there's no "OK I'm going to GC a million objects right in the middle of your scroll" performance dip but it will release all objects more gradually through ARC at a slightly bigger total performance cost.
Ask C devs why they (still) think Swift is a PITA to work with compared to Objective-C. Luckily in most scenarios you can use Objective-C mixed with Swift to get the advantages of both scenarios.
Haskell?
Or on today's HN: https://news.ycombinator.com/item?id=15582429
If Nim could mature a bit it would be really nice. There is OCaml but it is a bit goofy to work with if you prefer more imperative style coding. There is Go but no generics.
OCaml is a good choice. The ecosystem is definitely growing, though maybe not very quickly.
Nim[1] is a good alternative to Rust if you don't mind a GC, and I argue that even for use cases where a GC might be problematic it's still a good choice thanks to the Nim GC's soft real-time capabilities.
Now, my predicament: I love Rust's type system and tooling, but it's really hard to justify to myself the pain of writing correct Rust code (borrowing, lifetimes, etc.) when I know I can get almost the same effect by using a GC language + immutable messages.
And I don't need that last drop of performance either.
So if you just want a native language with a good type system and a growing ecosystem, where do you go? Still Rust or something else?