Hacker News new | past | comments | ask | show | jobs | submit | filmor's comments login

Well, Erlang has been picking up :)

- OTP27 added sigils[0], which allow you write UTF8 strings with just an additional tilde character

    ~"hallöchen" =:= <<"hallöchen"/utf8>>
- Also, since OTP27, Erlang's own documentation[1] is written in Markdown and created using ex_doc[2] - doc attributes etc. have been added in OTP27 as well, I think - You can use ex_doc in your own Erlang projects using rebar3_ex_doc for a while now[3]

I also miss the pipe operator, but there seems to be some opposition against it in Erlang-land (and it would need to be adjusted as Erlang's standard library doesn't put the "main" argument consistently in the first argument slot like Elixir does).

[0]: https://www.erlang.org/blog/highlights-otp-27/#sigils [1]: https://www.erlang.org/doc/readme.html [2]: https://hexdocs.pm/elixir/writing-documentation.html [3]: https://hexdocs.pm/rebar3_ex_doc/readme.html


On Gentoo, definitely. I really don't want to rebuild my whole system whenever some foundational library fixes a bug. It already annoys me quite a bit that I need to set up sccache to get half-way reasonable compile times out of Rust projects (and I'm saying that as someone who enjoys gradually replacing significant portions of the userspace with Rust tools).

This by itself is half the reason I think Nix's approach is a step backwards.

1Il (one, upper case i, lower case L) all seem to look alike in this font. For me, that disqualifies it as a coding font.


For me it has been running with minor issues and very few crashes for the last month as my daily driver on both my work (Fedora) and my private (Gentoo) laptop.


Mono has support for app domains (and is in general closer to .NET Framework), a more powerful C API and runs on more architectures.


This must be the reason. Wine seeks to be compatible with a bunch of legacy software, some of which will want to use the equivalent of .NET 1, 2, 3, and 4.x Framework and not just "dotnet core". (Or whatever the new thing is called in Microsoftese this week.)

Edit: maybe this means WPF can be the best way to write Linux applications. After all, Win32 is the stable Linux API... nudge nudge, wink wink. :-D


https://rerun.io/

Quite obvious, if you scroll to the "Getting Started" section.


Augustus, referenced in another top level comment, adds roadblocks to Caesar III (among other gameplay changes).


Where does it say that K-cars are not allowed on highways? I'm certain that I saw quite a few, and I can find no source that says otherwise.


Yes, kei cars are sure allowed to drive on highways.

> Their top speed limit even on highways is 100kmh

That's an old standard. They're allowed to go up to 120km/h on some roads.


The ? is not really the issue here. Rust is similar to C++ in that it encourages implicit resource management using scopes, so if you have resources that have to be free'd, you have to implement Drop somewhere.

The code would have looked just as correct and would have been just as wrong with the "old" non-sigil `try!(...)` syntax.


> The ? is not really the issue here.

Based upon the way the code was written, it was, at least in the mind of the author. They forgot they could exit scope there. They clearly didn't _intend_ for that outcome, but ended up with it anyways, possibly out of habit, and possibly because a single impactful sigil like that is easy to miss in review.

I get that technically it didn't cause the memory leak.. but just look at the way that was written initially... it obviously led to it _within_ that particular structure.


> They forgot they could exit scope there.

Their mistake was writing resource management code that requires manually thinking about where they might exit scope.


Just curious, would writing it in a better language have prevented this?


Slightly tongue in cheek answer: it is easy to write this kind of code in C++ without having C involved, hence style guides will usually have a prominent guideline specifically against this type of code[1].

In Rust, I think you only really run into this issue when interacting with C (or otherwise engaging in unsafe code), so for normal Rust coding it doesn't need to be spelled out as a guideline. And the Rustonomicon[2], the go-to resource for unsafe Rust, isn't really written as a set of guidelines. At least from a brief search, I found it harder to find a Rust page that specifically says "don't do this".

1: E.g. https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines..., the first guideline in the "resource management" section.

2: https://doc.rust-lang.org/nomicon/intro.html


This is a classic problem you can make in any language. If you were doing Java, and forgot to use `finally` for a resource, you'd have a leak due to an exception.

I do not know what metric you use to define "better"


`finally' is a word though, harder to forget than a single punctuation mark.


The dev did not "forget a single punctuation mark". It was there and it was correct. What was /not/ correct is that he did not implement any form of implicit resource freeing in an RAII-language. Doing resource management using scopes is a choice. It's not inherently better or worse than explicit resource management with something like Go's `defer`. But if that choice is made, as in Rust or C++, you have to ensure that the implicit resource management is correctly implemented (Drop in Rust, destructors in C++). Same as in Go, where you have to ensure that you call `defer` with the correct cleanup function or in C# where you have to use `using` on your disposables, etc.


The growable array type would use `realloc` when growing, which can make use of this internal information without exposing it.


Like most implementations, if you add items to a rust `Vec` one item at a time it doubles in size each time it hits its capacity (to make sure insert is amortized to O(1) even though each realloc potentially requires an O(n) memcpy). With the described allocator that would never lead to a cheap realloc.

It's even worse for types like HashMaps where reallocs can be much more expensive than just a big memcpy.


Also, Rust's Vec has the correct size hinting API, so we can say Vec::reserve(N) meaning that we expect to put as many as N more things into this Vec soon, or Vec::reserve_exact(X) meaning that we expect to put no more than X more things into this Vec, ever

With this distinct hint, reserve(N) preserves the amortized growth. Say we have total capacity 30, currently there are 20 items in the Vec, and Vec::reserve(20). So the advise is that the Vec may soon have up to 40 items, we should grow it. But since we weren't promised that's as big as it'll get, we grow it by doubling - to total capacity 60 items. If this is a pattern, repeatedly reserving space for 20 items and then adding them, this grows 30 -> 60 -> 120 -> 240 and so on, amortized growth as advertised - and growth is avoided when we're only "reserving" capacity we already have anyway.

Several languages, including C++ only provide the Vec::reserve_exact(X) feature, but name it reserve. Any such "reservation" is also implicitly promising there won't be further growth, so for our example it grows 30 -> 40 -> 60 -> 80 -> 100 -> 120 -> 140 ... our amortized growth strategy was destroyed and our performance will be much worse than O(1). In such a language students get taught not to use the reservation API to signal what they know and so they lose out on performance optimisations better than O(1)

I first ran into this feature because I was wondering about the over-allocation problem, and I realised this is solving a different but also important problem.


I have no idea what you are getting at. I just stated that you alloc/realloc what you require for your type. If you want to over-allocate, do it. But I don't see the need to know the size of the memory block that fulfilled your request.

That also gives the allocator the flexibility to use part of a block that it gave to you for someone else if that makes sense.

E.g. you request 200 bytes, a block of 256 bytes is actually allocated. Now you request with some other code 30 bytes. If the allocator had told you at allocation time "here are your 200 bytes, but just so you know, there's another 56" it could not hand the unused part of the 256 bytes to the next allocation.


> But I don't see the need to know the size of the memory block that fulfilled your request.

If we don't know, we can't use anything except what we asked for. For some allocations that's not important, but e.g. Vec can just upgrade the capacity to match, buffering mechanisms often may just as well use the entire available buffer not just the part they specifically asked for.

> E.g. you request 200 bytes, a block of 256 bytes is actually allocated. Now you request with some other code 30 bytes. If the allocator had told you at allocation time "here are your 200 bytes, but just so you know, there's another 56" it could not hand the unused part of the 256 bytes to the next allocation.

You're assuming that the allocator is able to remember that these extra 56 bytes are available. That may or may not be practical, it's a shame if we have to otherwise throw the 56 bytes away.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: