Live data from Hacker News

Swift is a more convenient Rust

blog.namangoel.com

261–270 of 318 posts

Re: Swift is a more convenient Rust

#261

Earlier quoted context omitted.

It's not the Standard ML of New Jersey of course, like I was taught last century, but it looks like an ML to me. Rust has a sound type system, whereas a language like C++ inherits C's YOLO approach to typing. In Rust Vec > is just a counter. Really, that's not theory that'll just happen by default because of how type arithmetic works. In C++ you can't even write down an equivalent type, let alone say how it would be…

I've looked for this optimisation, and while it makes sense to me (Infallible is unhabitable ==> s: Option can only exist if s = None ==> all values in vector must be of the same value None that is known ahead of time ==> store a counter of how many Nones are in the vector instead of each None as an entry into a traditional vec), I cannot find any trace of such optimisation, whether by reading into the bytes backing…

What's happening is that `Infallible` has no values, and cannot be instantiated. This results in `Option` only having one possible variant (None) which has no payload, and therefore being a zero-sized type.

Separately `Vec`, if `T` is a zero-sized type, never allocates and has a capacity of usize::MAX. Then, when you push into the Vec, because the value you push is zero-sized, there's no allocation and no data to write anywhere. Therefore the only effect is to increment the length counter.

Re: Swift is a more convenient Rust

#262

Earlier quoted context omitted.

Scoped enums ("enum class") are a very small improvement on the previous enum, the main thing they deliver is that they don't pollute your namespace as badly thanks to the scoping. Their notional status as "strict types" means nothing in a language which doesn't really care anyway, that's why memory_order::relaxed In Rust if you write nonsense like that it doesn't compile, these aren't comparable things. In C++ they'…

Oh come on now, everyone who programs in C++ knows operators don't work like that. Operators are tied to types, those enums don't have operator You also can't add them, or subtract them. Yes behind the scenes their integers, but almost certainly this is the case in Rust too. You can SOMETIMES coerce an enum class instance back to an int if you do unsafe casts (on purpose).

Both those scoped enums do in fact have operatorHowever whether you can add or subtract them is harder to guess than you seem to have assumed

https://godbolt.org/z/3vdazcr7E

Of course the bit pattern representation is the same in Rust. The point isn't the representation or we'd be talking about machine code. The point is the ergonomics.

These types aren't (shouldn't be) integers, but in C and C++ they are anyway.

Re: Swift is a more convenient Rust

#263
post #134
post #96

Earlier quoted context omitted.

Rust is more popular than all of these languages except swift combined. So it seems empirically that ergonomics and expressiveness don't matter that much or these languages don't manage to do significantly better than rust.

It appears more popular, which isn't the same thing.

If you have better metrics then that's interesting, otherwise it just looks bitter.

Yeah, maybe chicken nuggets only appear more popular than broccoli. But I think since we don't have any actual evidence to say otherwise we can assume that's because they are in fact more popular than broccoli.

Re: Swift is a more convenient Rust

#264

Earlier quoted context omitted.

Most GC langs have these features too they're just not in your face. Technically C# has true value types like C++. Rust makes the distinction between stack and heap references, like C++. Other, more high-level languages don't - there's only one kind of reference, you can't take a reference to a stack object. Maybe you implement that by making all objects heap allocating (Java) or you just say they have to be copied e…

The assessment on C# does not match language spec at all. Not only instance methods on C# structs are implicitly byref, you can easily pass structs by reference via ref, out and in keywords. On top of that, ref structs can hold `byref` pointers aka 'ref' keyword which can point to arbitrary memory, or have references to other structs/variables/anything. There is also regular C syntax with &T and T* for unmanaged refe…

Wow, I was not aware of the monomorphization of structs in C#. That's very interesting, I wonder how you're able to mix generic structs and generic classes seamlessly.

> you can easily pass structs by reference via ref, out and in keywords. On top of that, ref structs can hold `byref` pointers aka 'ref' keyword which can point to arbitrary memory

These are not features I've encountered. I wonder how you solve dangling references when those references could point to automatic stack variables.

Re: Swift is a more convenient Rust

#265

Earlier quoted context omitted.

The assessment on C# does not match language spec at all. Not only instance methods on C# structs are implicitly byref, you can easily pass structs by reference via ref, out and in keywords. On top of that, ref structs can hold `byref` pointers aka 'ref' keyword which can point to arbitrary memory, or have references to other structs/variables/anything. There is also regular C syntax with &T and T* for unmanaged refe…

Wow, I was not aware of the monomorphization of structs in C#. That's very interesting, I wonder how you're able to mix generic structs and generic classes seamlessly. > you can easily pass structs by reference via ref, out and in keywords. On top of that, ref structs can hold `byref` pointers aka 'ref' keyword which can point to arbitrary memory These are not features I've encountered. I wonder how you solve danglin…

> Wow, I was not aware of the monomorphization of structs in C#. That's very interesting, I wonder how you're able to mix generic structs and generic classes seamlessly.

The handling is transparent, in a way. As implemented by CoreCLR, class-type generic arguments have shared representation named __Canon. This means that, for example, a `Dictionary` has a generic instantiation indicated as `Dictionary` where __Canon is an implicit generic type argument passed alongside relevant calls. Statics referencing that do get exact address, and there is quite a bit of complexity regarding runtime handling of this as far as virtual calls and other edge cases are involved, but as a programmer you are never exposed to that directly. It's an implementation detail, and even un-monomorphized cases work rather fast in most situations, like standard data containers.

> These are not features I've encountered. I wonder how you solve dangling references when those references could point to automatic stack variables.

Not sure what you mean by automatic stack variables, but the idea behind byref pointers\managed references\'ref's is that they are not allowed to be boxed or otherwise placed on the heap.

This lifetime restriction enables key scenarios:

- byrefs can point to object interiors without hindering GC throughput

- byrefs can point to stack memory, allowing `var span = (stackalloc byte[32]);` and more

- byrefs can point to any unmanaged memory without requiring excessive range checks by GC

This way you can use `ref T` to represent any memory location and `Span` to represent any contiguous memory range up to 2B elements, without having to carry around bespoke overloads and types that disambiguate between containers and memory sources, much like you would usually see in most other GC-based languages.

There is also additional lifetime analysis in Roslyn to prevent you from returning 'scoped' 'ref's to an outer scope, like having a ref point to an integer in the current method body and returning it to the caller - this will not compile, unless you override it with unsafe [UnscopedRef] which you should never do unless you are absolutely certain (every time I used it and was absolutely certain, the compiler was right and I was not :D). This also works "through" ref structs and other tricky scenarios, which means you can return a ref that points to a middle of heap-allocated array - the scope of object exceeds current method, and byref can keep the array rooted even if no other reference to it exists. The main restriction is byrefs can mostly flow "downward" as not to escape the scope they originate from, but that's a given in most scenarios in Rust just as much.

There is a basic walkthrough about byrefs here: https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...

C# is good at systems programming - it also has portable SIMD and intrinsics, static linking, native compilation and zero-cost FFI. Engineers getting surprised by this fact rather than upset is the happier but unfortunately less frequent outcome :)

Re: Swift is a more convenient Rust

#266
post #129

Earlier quoted context omitted.

In this context, ML is Meta Language: https://en.wikipedia.org/wiki/ML_(programming_language)

Thank you! The whole time I was like "what in the absolute hell is a ML language".

I've heard so much about Machine Learning in recent years, that I couldn't fathom ML be used in any other context & be understood.

Re: Swift is a more convenient Rust

#267
post #223

Earlier quoted context omitted.

thanks, i'm bad at abbreviations and don't like when people just throw them like this without first using the whole term at least once

Expanding this abbreviation conveys zero information. It’s a programming language named ML, and if you haven’t heard of it then giving the etymology of the name isn’t going to help.

It clarifies it's not something else I've heard of (markup language, machine learning). The ML abbreviation shares the space with other terms so it can be confusing. Compare it to HTML which is 1) more popular and 2) unique in the context of programming.

Re: Swift is a more convenient Rust

#268
post #259

Earlier quoted context omitted.

The stack is fully automatic arbitrary memory and has nothing to do with registers. You can allocate as much as you want (including e.g. bytearrays), until you run into the allocated stack limit. That limit can be arbitrary, and some languages even dynamically scale the stack. That you also have access to manual memory on the heap doesn’t matter. You can also do manual memory management in Rust if you want, as one ha…

Ok. Then manual memory applies to just heap memory management. It's not rocket science. If you are calling malloc/free to maintain your memory you're doing manual memory management. > You can also do manual memory management in Rust You can do Garbage Collection in C, it doesn't make it Garbage Collected language. You're confusing default memory management with what's possible. By your logic, Arena allocators can be…

> It's not rocket science. If you are calling malloc/free to maintain your memory you're doing manual memory management.

Sure, and when I do the same in Rust I'm also doing manual memory management. So by your definition, both Rust and C are manual memory languages.

> You're confusing default memory management with what's possible.

Ah, so we care about the default, which I pressume is what the language semantics themselves provide, rather than focusing on what the standard libraries can provide you?

In that case C is an automatic memory language, because the language semantics only provide you stack memory. malloc/free are just random functions in the standard library after all, just like Rust's `Box::new` and `std::alloc`.

See, the point is that you're opting into manual memory management in C from an automatic model. We are so used to the stack that we forget that it's the OG fully automatic zero-cost memory management system, and in case of C++, can be used to implement fully automatic heap memory as well - in which case you never need to call malloc/free/new/delete.

(And no, it doesn't count that your smart pointer calls new/delete, because then you also need to count Box::new calling std::alloc)

> By your logic, Arena allocators can be used in many different languages, including GC ones like Java.

Uh, even in bog standard Java without any shenanigans you are using an "arena allocator". A GC doesn't change how allocators work, it just responsible for calling free.

(Caveat about moving vs. non-moving garbage collectors and ones that have multiple arenas, but that's not relevant here and an entire topic of its own.)

Re: Swift is a more convenient Rust

#269
post #80

Earlier quoted context omitted.

Rust is not really an ML language, is it? &mut is a very noticeable difference. Calling Rust, Scala, Swift and Kotlin ML seems to be taking it too far. Scala and Kotlin even have all the traditional OOP features. You might just as well put C++ in the ML list.

It's not the Standard ML of New Jersey of course, like I was taught last century, but it looks like an ML to me. Rust has a sound type system, whereas a language like C++ inherits C's YOLO approach to typing. In Rust Vec > is just a counter. Really, that's not theory that'll just happen by default because of how type arithmetic works. In C++ you can't even write down an equivalent type, let alone say how it would be…

Could you explain the semantics of Vec>? What would exist in the memory pointed to by the Vec? What would be the use case for this type?

Re: Swift is a more convenient Rust

#270

Earlier quoted context omitted.

Both ARC and garbage collection are memory management techniques. ARC does not equal garbage collection though. Garbage collection runs at intervals and is triggered by certain signals (memory pressure, etc), pauses all threads and scans for objects that can be deallocated. It is a very different concept than ARC.

ARC is a method of implementing garbage collection, and is discussed as such in academic literature. What you are equating with "garbage collection" is Mark-Sweep, which is an another way to implement GC, with a very different set of tradeoffs. (Broadly, better throughput at the expense of higher latency.)

In common usage everyone understands that GC = tracing GC.
Post reply on HN