Live data from Hacker News

Rust 1.46

blog.rust-lang.org

141–150 of 157 posts

Re: Rust 1.46

#141

> if, if let, and match > while, while let, and loop > the && and || operators Common Lisp user here. Why just that? How come you can’t have the entire language as well as all your language customizations available at compile time for evaluation?

You can! Just not through `const fn`. Rust has macros, which at their limit are capable of running arbitrary Rust code that manipulates syntax and communicates with the compilation process, just like in a good old Lisp.

Why isn’t `const fn` like this too? One word answer: determinism. Rust takes type/memory/access/temporal safety very seriously, and consequentially you can’t use anything in a `const fn` that isn’t fully deterministic and doesn’t depend in any way on platform-specific behavior. This includes, for example, any floating-point computation, or any random number generation, or any form of I/O, or handling file paths in an OS-specific way, or certain kinds of memory allocation. The span of things possible in `const fn`s has been expanding over time, and will in the nearish future largely overtake C++’s direct counterpart of it (`constexpr` functions) in capability. But some things will intentionally never be possible in `const fn`s, for the reasons given above.

Re: Rust 1.46

#142

Earlier quoted context omitted.

Julia might be a better fit for this use case. That way you leverage a more developed data ecosystem, can call python when necessary and avoid writing low level code. Depends on the task of course.

I’m fascinated by Julia and have test driven it before but it didn’t click for me. Maybe I was doing it wrong and/or the ecosystem has matured since I last looked. I guess I generally do like the pythonic paradigm of an interpreted glue language orchestrating precompiled functions written in other languages. I don’t need or want to compile the entire pipeline end to end after every edit, that slows my development ite…

If the dev cycle feels slow in julia, you can make it snappier with a tool like Revise.jl, it is quite handy.

If you just need to fill a small and slow gap maybe something like numba is also a good option to stay within python.

Going all the way to a low level language would require the compilation, the glue code and expertise in both languages. Probably that slows down the development pipeline more than the JIT compilation from julia or numba.

Anyway, any opportunity to learn/practice some rust is also great!

Re: Rust 1.46

#143
post #80
post #71

Earlier quoted context omitted.

I think that Rust is often assumed to be functional because it has ADTs and nice pattern matching, both of which have historically been a feature specific to FP. Just goes to show how fuzzy our definition of FP really is...

Agreed. Same with "OOP". Who the hell knows what people really mean when they say that. Those people who think that "FP" means "type system like Haskell" are wrong, though, IMO. It precludes languages that are much more function-based, such as Clojure, Schemes, Elixir.

Usually when the term OOP is used, it actually means ClassOrientedProgramming (C++/Java/C# etc)

Re: Rust 1.46

#144

Earlier quoted context omitted.

This is a complex topic, but what it boils down to is that the function signature is the API. If you borrow the whole thing, you borrow the whole thing, not disjoint parts of it. This is also why it's okay in the body of a single function; that doesn't impact a boundary. We'll see what happens in the future.

My preferred solution to this is to make partial borrows part of the method definition syntax to make it clear this is part of the external contract of your API. Also I lean towards mimicking the arbitrary self type syntax and land on something along the lines of impl Foo { fn bar(self: Foo { ref a, mut ref b, .. }) {} } Where that signature tells the borrow checker that those two fields are the only ones being acces…

On one hand this looks/feels absolutely useful and kind of "must have" feature, yet the boilerplate seems excessive. But at the same time it's absolutely something that should be described somewhere as metadata for a function. It seems to me this should be something that the compiler figures out and mostly elides, like lifetimes. (But this should be present as part of API, should be easily discoverable, should be there at compile time when linking against crates, etc.)

Re: Rust 1.46

#145

Earlier quoted context omitted.

I'm far from an expert, but I would not expect hand-written Rust code to outperform Numpy. Not because it's Rust and Numpy is written in C, but because Numpy has been deeply optimized over many years by many people and your custom code would not have been. When it comes to performance Rust is generally comparable to C++, as a baseline. It's not going to give you some dramatic advantage that offsets the code-maturity…

I deal with a lot of ragged data that is hard to vectorize, and currently write cython kernels when the inner loops take too long. Sounds like Rust might be faster than cython? Thanks for the feedback.

Also it might take 20x less RAM compared to using Python objects like sets and dicts. In Rust there's no garbage collection, and you can lay out memory by hand exactly as you want.

Re: Rust 1.46

#146
post #144

Earlier quoted context omitted.

My preferred solution to this is to make partial borrows part of the method definition syntax to make it clear this is part of the external contract of your API. Also I lean towards mimicking the arbitrary self type syntax and land on something along the lines of impl Foo { fn bar(self: Foo { ref a, mut ref b, .. }) {} } Where that signature tells the borrow checker that those two fields are the only ones being acces…

On one hand this looks/feels absolutely useful and kind of "must have" feature, yet the boilerplate seems excessive. But at the same time it's absolutely something that should be described somewhere as metadata for a function. It seems to me this should be something that the compiler figures out and mostly elides, like lifetimes. (But this should be present as part of API, should be easily discoverable, should be the…

The problem with having the compiler figure it out is that the signature now becomes dependent on implementation details that can't be seen from the signature, and could be accidentally changed. This information must be an explicit part of the signature, so that it's properly visible and spells out what the function can do without having to read the body.

That said, I think putting it in the argument list like that is a terrible idea. It would add far too much clutter. What if it was put into the where section, sort of like this:

  impl Foo {
      fn bar(&mut self, other_param: &Data)
        where self: borrows{ a, b, .. },
              other_param: borrows{ a, b, ..},
      {
        // Function body
      }
  }
In one sense, it sort of fits because it's providing a "bounds" of sorts on how the reference can be used, similar to the way a trait bound would for a type. If no reference binding is provided it would default to borrowing all the fields, which is the current behaviour.

Re: Rust 1.46

#147

Earlier quoted context omitted.

I’m fascinated by Julia and have test driven it before but it didn’t click for me. Maybe I was doing it wrong and/or the ecosystem has matured since I last looked. I guess I generally do like the pythonic paradigm of an interpreted glue language orchestrating precompiled functions written in other languages. I don’t need or want to compile the entire pipeline end to end after every edit, that slows my development ite…

If the dev cycle feels slow in julia, you can make it snappier with a tool like Revise.jl, it is quite handy. If you just need to fill a small and slow gap maybe something like numba is also a good option to stay within python. Going all the way to a low level language would require the compilation, the glue code and expertise in both languages. Probably that slows down the development pipeline more than the JIT comp…

One thing that may help with the glue-code aspect would be a crate like pyo3[0], which can generate a lot of the details for you.

[0] https://crates.io/crates/pyo3

Re: Rust 1.46

#148
post #138
post #63

Earlier quoted context omitted.

I realized after I wrote the comment that I was really referring to the closure traits when I said that. And I really should have said "kind" instead of "type" because, like you said, every different function has its own type . But anyway, I don't really disagree with your point about categorizing languages as OOP, Procedural, or Functional. But honestly, in this case, I think it's pretty damn clear than Rust is proc…

But honestly, in this case, I think it's pretty damn clear than Rust is procedural WAY more than it's either OOP or FP. (Note: By OOP, I mean Java-style with tall ownership hierarchies and object-managed mutable state, not necessarily caring about inheritance. And definitely not referring to Alan-Kay-Style-OOP a la Lisp and Smalltalk). Scala can be looked at ... Interesting perspectives, and I largely agree with all…

> Related: I heard someone else say that while Clojure and Erlang embrace immutability for concurrency, Rust shows that you can "just mutate". It's still safe for concurrency (due to its type system).

Yes! I will repeat a sentiment I articulated on Reddit about that. Even after having used Rust on a handful of small-to-medium sized projects since 2016, I never realized that I could loosen/abandon my immutability fetish that I had been trained to love over the years of working with C++ and Java. C++ needs it for concurrency, and Java needs it for concurrency and because every method can mutate its inputs without telling you. Rust doesn't have either of those problems. Having immutable-by-definition objects in Rust isn't really that useful (unless, of course, the thing is naturally, semantically, immutable anyway, like a Date IMO). It was an eye-opening epiphany and I'm excited for my next Rust session to see how my "new worldview" pans out. :)

Re: Rust 1.46

#149
post #143
post #80

Earlier quoted context omitted.

Agreed. Same with "OOP". Who the hell knows what people really mean when they say that. Those people who think that "FP" means "type system like Haskell" are wrong, though, IMO. It precludes languages that are much more function-based, such as Clojure, Schemes, Elixir.

Usually when the term OOP is used, it actually means ClassOrientedProgramming (C++/Java/C# etc)

Which I also don't understand. Is that a style of overusing classes where functions would suffice (FooHelper)? Or is it something about the language? Because almost all popular languages have classes. Rust and Go call them "struct", but it's the same thing. Swift has "class" and "struct", but they're both the same thing as a C++ class.

Re: Rust 1.46

#150
post #2

The most exciting component of this release is the const fn improvements. With loops and if available, you can now do non-trivial computation in const fn for the first time. It reduces the gap between Rust's const fn and C++'s constexpr to a large degree. Ultimately, the miri execution engine that this feature builds upon, supports a much larger set of features that even constexpr supports. It's been a project spanni…

I wonder why && and || are not allowed in const functions? > All boolean operators except for && and || which are banned since they are short-circuiting. I guess I'm missing something obvious but why does the short circuiting break const-ness?

[deleted]
Post reply on HN