News for hackers. Stuff that matters.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by lmm on Friday August 19, 2016 @01:20PM (#12321662)
It seems like a lot of work? In scala this would just be:

    val codes = (data_table, code_lengths, code_table).zipped map HuffmanCode
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by mtanski on Friday August 19, 2016 @01:21PM (#12321678)
Rust is not Scala
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by lmm on Friday August 19, 2016 @01:27PM (#12321728)
It's not, but they're both ML-family languages. I had hoped that Rust would be able to offer a similar level of elegance to Scala.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by pcwalton on Friday August 19, 2016 @01:48PM (#12321894)
The biggest difference between Scala and Rust here is ".iter()", which is necessary mainly because you need to specify whether the iterator iterates over references (".iter()") or passes results by value (".into_iter()"). Because Java doesn't have value types and has no concept of move semantics, it has no need for the distinction, while Rust does.

In effect, the "elegance" of Scala here is really the product of its heavy GC dependence. So the comparison isn't as meaningful as it might seem.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by eddyb on Friday August 19, 2016 @06:04PM (#12323846)
The example can be written like this though:

  let codes: Vec<HuffmanCode> = data_table.iter()
            .zip(&code_lengths)
            .zip(&code_table)
            .map(|((&value, &length), &code)| {
                HuffmanCode {
                    length: length,
                    code: code,
                    value: value,
                }
            })
            .collect();
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by Veedrac on Saturday August 20, 2016 @01:20AM (#12325337)
In fact `code_lengths` and `code_table` are never used again so should just be passed by value, which saves four more `&`s.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by saosebastiao on Friday August 19, 2016 @02:45PM (#12322422)
Wouldn't the type guarantees provided by rusts type system allow for different implementations based on whether it was called on value types vs reference types? I thought there was an auto specialization feature created a while ago that did something like that.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by Tuna-Fish on Friday August 19, 2016 @03:37PM (#12322884)
It allows changing implementation depending on what you pass it, but it cannot change how you pass things. The issue is that if you just call zip(code_lengths), then ownership of code_lengths is passed into the function and it ceases to work in it's parent.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by foota on Friday August 19, 2016 @03:30PM (#12322827)
I think the into iterator version borrows the references (did I say that right?
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by nercury on Friday August 19, 2016 @01:36PM (#12321804)
Looking at the example, I can't find a thing in there that is not required (except the obvious `:Vec<_>` type that is not required). We need `.iter` to tell that iterator is imutable (there is mutable version), we need `.collect` to actually run the iteration. I also don't think objects should have default constructor functions.

It may be possible to implement `.zipped` on tuples though.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by epidemian on Friday August 19, 2016 @01:52PM (#12321931)
Yep, but it's still an unfortunately big difference in expressiveness between the two languages, where one might think that they would be more or less on par, given the languages' similarities (both are more or less contemporary in their design, statically typed, with similarly powerful type systems, etc).

My question is then: is there something fundamentally preventing Rust from achieving similar levels of expressiveness to this Scala example without incurring in unnecessary runtime overhead? Given that both languages are statically typed, my inclination would be to say no: the information is there, the compiler should be able to figure it out. But, alas, i know very little about these things, hence my question :)

Update: pcwalton gave some nice insight on why Rust needs some of these constructs on an uncle comment.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by Veedrac on Saturday August 20, 2016 @01:54AM (#12325404)
Actually Rust already has izip and IntoIterator that covers the early differences. The type annotation `Vec<_>` is also optional since it can be inferred from the context.

The `map` is uglier in Rust because

* the comparison was against a constructor with positional, rather than named, arguments

* the Scala code didn't need to dereference any arguments, and

* and Scala's `Zipped` is a special type with a special `map` function that takes three arguments, unlike a normal iterator.

The first and last points could be easily copied in Rust: you'd build a constructor for HuffmanCode and augment iterators of tuples with with a starmap method (that can be done in a library). The middle point can be done before the zipping. The result would be

    let codes =
        izip!(data_table.iter().cloned(), code_lengths, code_table)
            .starmap(HuffmanCode::new)
            .collect();
Rust's collect is never implicit, like Scala's CanBuildFrom. This prevents accidental collects, which helps writing fast code, but in principle I don't see why it couldn't be implicit - it would just require the whole standard library to be overhauled.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by Veedrac on Saturday August 20, 2016 @01:36AM (#12325359)
Actually the last two `.iter()` aren't needed at all because of IntoIter. All three can all be removed if you use Itertools' izip!

    let codes: Vec<_> =
        izip!(&data_table, code_lengths, code_table)
            .map(|(&value, length, code)| {
                HuffmanCode {
                    length: length,
                    code: code,
                    value: value,
                }
            })
            .collect();
(If HuffmanCode was a tuple type, this could even be

    #![feature(fn_traits)]

    let codes: Vec<_> =
        izip!(data_table.iter().cloned(), code_lengths, code_table)
            .map(|args| (&HuffmanCode).call(args))
            .collect();
but now I'm just playing around.)
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by steveklabnik on Friday August 19, 2016 @01:44PM (#12321862)

  > (except the obvious `:Vec<_>` type that is not required)
It is required, otherwise, `collect()` doesn't know what type of collection to collect into.

  > It may be possible to implement `.zipped` on tuples though.
This is impossible without varargs, no?
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by pcwalton on Friday August 19, 2016 @01:50PM (#12321908)
> This is impossible without varargs, no?

Nah, you'd just implement it as an impl over and over on tuples of reasonable size (up to 16 or so).

It wouldn't be elegant, but it'd work in practice.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by cbreeden on Friday August 19, 2016 @08:04PM (#12324361)
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by steveklabnik on Friday August 19, 2016 @01:52PM (#12321922)
Oh right, I see now.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by __s on Friday August 19, 2016 @08:41PM (#12324467)
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by nercury on Friday August 19, 2016 @01:54PM (#12321943)
> `collect()` doesn't know what type of collection to collect into.

Yes, unless there is some other mention of Vec, i.e. it is returned from the function.

> This is impossible without varargs, no?

Varargs would definitely help, and would allow Rust to borrow more ideas without workarounds. But one can do it manually for each tuple variant.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by nimish on Friday August 19, 2016 @01:58PM (#12321971)
Haskell just brute force implements zipWith3, zipWith4 etc

Not elegant, but it works.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by tome on Friday August 19, 2016 @03:53PM (#12322981)
The un brute force way is to use the Applicative instance of ZipList.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by bluejekyll on Friday August 19, 2016 @01:31PM (#12321755)
Scala and Rust are not trying to solve problems in the same way though. Rust is a zero-overhead language. Scala has never tried to make that claim.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by gmfawcett on Friday August 19, 2016 @01:41PM (#12321847)
It's a bit of a stretch to call Scala and Rust "ML-family languages".
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by cfallin on Friday August 19, 2016 @04:19PM (#12323165)
Not at all -- there's a lot of commonality in the language designs.

Core language features: both have algebraic datatypes like ML ("case classes" in Scala, enums in Rust), and a 'match' statement that makes working with them easy. Both have pervasive destructuring that works with match arms, 'let' bindings, etc.

Data structures and mutation: both encourage a pragmatic version of immutability -- use values and provide functional interfaces primarily, but support mutation where needed. In Rust there are 'Cell' and 'RefCell' types, just like ML's cell-based interior mutability.

Library idioms: all three have the standard set of functional-style higher-order transformation functions ('map', 'filter', etc. -- Rust in particular has a very rich Iterator trait API), and it's idiomatic to use these.

FWIW, Rust's first/bootstrap compiler was written in OCaml and there's a lot of obvious influence.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by gmfawcett on Friday August 19, 2016 @04:36PM (#12323275)
I'm aware that Rust's bootstrap compiler was written in Ocaml. And yes, there are lots of ML inspirations in the language -- but not enough to make an ML language. Where are the module functors, for example? Many would consider that an essential element of an ML language, and it is a stretch to call a language an ML family member without them.

I don't want this to devolve into a No True Scotsman debate, I just feel that the parent post -- which decried a lack of similarity between Rust and Scala because they were both in the ML family -- was founded on a weak premise.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by saosebastiao on Friday August 19, 2016 @04:51PM (#12323372)
A module functor is nothing more than a higher order module...one that takes as a parameter some data structure that conforms to an interface (signature). Rust may not have constructs called module functors, but it definitely has constructs that are capably equivalent, as well as some that are even more powerful (a claim that applies to Scala as well)

For me, type inference, strong typing, and ADTs with pattern matching puts a language into the ML family quite easily.

Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by gmfawcett on Friday August 19, 2016 @05:24PM (#12323573)
All right, I concede.:) Thanks for sharing your views.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by bjz_ on Friday August 19, 2016 @11:21PM (#12325000)
Module functors were an SML feature - not really in the original 'ML' language. I would put Haskell in the ML family, and it doesn't have module functors. Rust has type inference, and a core type syntax and semantics that is heavily inspired by it.
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by Tyr42 on Friday August 19, 2016 @08:59PM (#12324517)
I mean, Haskell doesn't have module functors, and I'd certainly claim Haskell is in the ML family. If Haskell isn't, what would be?
Re:Writing a JPEG Decoder in Rust – Part 2: Implementation I by premium-concern on Friday August 19, 2016 @04:42PM (#12323313)
I think ML-family is fine. Scala is much closer to ML than what people sort into the Algol-family or C-family groups.