These are chat archives for rust-lang/rust

13th
May 2017
Fra ns
@snarf95_twitter
May 13 2017 07:53
in C# you'd do: $"{p.First} {p.Last} is {p.Age} years old."
David McGillicuddy
@djmcgill
May 13 2017 08:11
it's done via macro like (from that page)
format!("Hello");                 // => "Hello"
format!("Hello, {}!", "world");   // => "Hello, world!"
format!("The number is {}", 1);   // => "The number is 1"
format!("{:?}", (3, 4));          // => "(3, 4)"
format!("{value}", value=4);      // => "4"
format!("{} {}", 1, 2);           // => "1 2"
format!("{:04}", 42);             // => "0042" with leading zeros
Andrey Lesnikov
@ozkriff
May 13 2017 08:12
that's not how interpolated strings work in C#
David McGillicuddy
@djmcgill
May 13 2017 08:12
It's more of a printf style than directly putting it inline in the strings.
Andrey Lesnikov
@ozkriff
May 13 2017 08:13
you can't do let value = 4; format!("{value}"); in rust as far as I know
rust-lang/rfcs#1250
Fra ns
@snarf95_twitter
May 13 2017 08:27
why is this not possible? for index in 3..0 { }
Fra ns
@snarf95_twitter
May 13 2017 08:36
why isn't it possible to join or concat on a iterator?
in C# you can do String.Join("seperator", whatever-enumerable);
red75prime
@red75prime
May 13 2017 08:53

for index in (0..3).rev() { }

You can use itertools crate https://docs.rs/itertools/0.6.0/itertools/trait.Itertools.html#method.join

As for 'why', it requires too much speculation to answer.
Fra ns
@snarf95_twitter
May 13 2017 08:57
    let result: Vec<String> = (verse_to..(verse_from+1))
        .rev()
        .map(|i| (&verse(i)).clone())
        .collect::<Vec<String>>();
    result.as_slice().join("\n")
this code looks horrible, any advice?
var result = String.Join("\n", Enumerable.Range(verseFrom, verseTo).Reverse().Select(i => verse(i));
how it would look in C#
Denis Lisov
@tanriol
May 13 2017 09:04
What type does verse return?
Fra ns
@snarf95_twitter
May 13 2017 09:06
a String
Denis Lisov
@tanriol
May 13 2017 09:07
Then you don't need .map(|i| (&verse(i)).clone()) and should be able to use .map(verse)
Fra ns
@snarf95_twitter
May 13 2017 09:07
actually it could be written as
let result = (verse_to..verse_from+1).rev().map(verse).collect::<Vec<_>>().join("\n")
thx
Sherzod Mutalov
@shmutalov
May 13 2017 09:12
In c# you dont need to .Select(i => verse(i)) to :P You can write just .Select(verse)
Fra ns
@snarf95_twitter
May 13 2017 09:13
tru dat
Fra ns
@snarf95_twitter
May 13 2017 11:41
why is .collect::<Vec<_>>() necessary? I mean why isn't it possible to join on an iterator?
Jonas Platte
@jplatte
May 13 2017 12:09
@snarf95_twitter It is actually possible. As @red75prime wrote, itertools has a join method. It's just not in the standard library (yet).
red75prime
@red75prime
May 13 2017 12:10
@snarf95_twitter join for Iterator<Item=U>, U: Copy can be implemented relatively easily https://play.rust-lang.org/?gist=8339f4b984ba66df8c84c973eb282ed8&version=stable&backtrace=0
Why it isn't implemented in standard library? I don't know. Maybe no one deemed it important enough to submit a PR to include it.
Joonas Koivunen
@koivunej
May 13 2017 12:25
itertools has join https://docs.rs/itertools/0.6.0/itertools/fn.join.html which might be one reason why I can't find an RFC or PR for this to be in std
Fra ns
@snarf95_twitter
May 13 2017 12:29
why can't I do (1..range_end).sum()?
Jonas Platte
@jplatte
May 13 2017 12:35
@snarf95_twitter You should be able to, what's the error message?
red75prime
@red75prime
May 13 2017 12:36
let s: i32 = (1..20).sum();
Fra ns
@snarf95_twitter
May 13 2017 12:36
the trait std::iter::Sum<u8> is not implemented for u32
Jonas Platte
@jplatte
May 13 2017 12:37
Okay, so you're trying to sum a bunch of u32s into one u8?
That seems like a bad idea :D
Fra ns
@snarf95_twitter
May 13 2017 12:38
no its the other way around u8 -> u32
Jonas Platte
@jplatte
May 13 2017 12:39
oohh, right
That's interesting that that doesn't work
red75prime
@red75prime
May 13 2017 12:40
convert u8 into u32. .map(|v|v as u32).sum() or .map(|&v|v as u32).sum()
Fra ns
@snarf95_twitter
May 13 2017 12:41
thx
Jonas Platte
@jplatte
May 13 2017 12:43
It is weird that there are no impl Sum<uX> for uY where X < Y
Fra ns
@snarf95_twitter
May 13 2017 12:45
that sure would be convenient
Fra ns
@snarf95_twitter
May 13 2017 14:30
Why must I call iter() on a vec?
Because no method overloading right? But why no method overloading?
Joonas Koivunen
@koivunej
May 13 2017 14:32
@snarf95_twitter calling .iter() on any collection will create you a value that keeps track of the position inside the vec for example; if this was a feature of the collection itself you couldn't have multiple iterators created to the same collection at the same time
Jarred Nicholls
@jnicholls
May 13 2017 14:32
@snarf95_twitter No, it is because Vec implements IntoIterator using move semantics (items are moved out of it). iter() returns an Iterator that has reference semantics (references items within the Vec, doesn't move them out)
Fra ns
@snarf95_twitter
May 13 2017 14:37
I see... it's just that it makes code look more cluttered than it needs to be, when you're only querying the vec...
Fra ns
@snarf95_twitter
May 13 2017 14:45
im not sure I understand tbh, if the vec is immutable then move shouldn't be possible right?
Joonas Koivunen
@koivunej
May 13 2017 14:53
@snarf95_twitter i remember being confused about these as well: owned values can be moved or borrowed, mut allows borrows, mutable borrow and mutation. they are more orthogonal than on the same axis
Jarred Nicholls
@jnicholls
May 13 2017 14:53
Your variable (aliasing the vec) is immutable, so the Vec can't have any of its mutating methods called on it. That is not the same as move. An immutable variable can be moved (it's not being mutated, it's being consumed). Vec's IntoIterator moves the Vec into its into_iter() method, consuming it. So that means items inside of Vec are no longer owned by the Vec and can/will be moved out (otherwise they will be dropped).
bigDaddyS1oth
@bigDaddyS1oth
May 13 2017 15:35
Hey Rustceans, are there any decent free resources that are good for learning Rust? Learn Rust in Y Minutes isn't...well very helpful. exercism.io is great if I knew the structure of Rust better.
Ilya Bogdanov
@vitvakatu
May 13 2017 15:36
@bigDaddyS1oth hi there! You can use rust by example or The book (or both)
bigDaddyS1oth
@bigDaddyS1oth
May 13 2017 15:45
@pnkfelix sweet! Thanks!
Fra ns
@snarf95_twitter
May 13 2017 19:50
pub fn encode(input: &str) -> String {
    let runs = input
        .chars()
        .fold(Vec::<(char, u8)>::new(), |mut acc, c| {
            if let Some(last) = acc.iter().cloned().last() {
                if last.0 == c {
                    acc.pop();
                    acc.push((last.0, last.1 + 1));
                } else {
                    acc.push((c, 1));
                }
            } else {
                acc.push((c, 1));
            }
            acc
        });

    runs.iter()
        .map(|x| if x.1 > 1 {
                 format!("{}{}", x.1, x.0)
             } else {
                 format!("{}", x.0)
             })
        .collect::<Vec<_>>()
        .join("")
}
I'm trying to do simple RLE-compression using map and fold... Any advice on how to avoid pop/push? or avoid cloning of acc
Denis Lisov
@tanriol
May 13 2017 20:40
acc.iter().cloned().last() - don't do that, it'll kill your performance!
David McGillicuddy
@djmcgill
May 13 2017 20:42
You need to split up the borrow of acc into two parts - one where you get (and copy) the character to test against, and one to actually edit acc.
But the last element is copy :)
pub fn encode(input: &str) -> String {
    let mut chars = input.chars();
    match chars.next() {
        None => "".to_string(),
        Some(first_char) => {
            let initial_state = vec!((first_char, 1)); 
            let runs = chars.fold(initial_state, |mut acc, c| { // acc is never empty
                let &(last_char, _) = acc.last().unwrap();
                if last_char == c {
                    (*acc.last_mut().unwrap()).1 += 1
                } else {
                    acc.push((c, 1))
                }
                acc
            });

            runs.iter() // from here on the same as yours
Fra ns
@snarf95_twitter
May 13 2017 20:47
woah thats awesome, thanks
David McGillicuddy
@djmcgill
May 13 2017 20:51
The initial_state thing isn't strictly necessary but it's a lot cleaner and could potentially be more efficient (but I suspect all those if acc.len() == 0 checks would get optimised out anyway).
Actually since you're mutating acc anyway the fold is redundant and can be replaced with a loop:
pub fn encode(input: &str) -> String {
    let mut chars = input.chars();
    match chars.next() {
        None => "".to_string(),
        Some(first_char) => {
            let mut acc = vec!((first_char, 1)); // acc is never empty
            for c in chars {
                let &(last_char, _) = acc.last().unwrap();
                if last_char == c {
                    (*acc.last_mut().unwrap()).1 += 1;
                } else {
                    acc.push((c, 1));
                }
            };

            acc.iter()
            .map(|x| if x.1 > 1 {
                     format!("{}{}", x.1, x.0)
                } else {
                     format!("{}", x.0)
                })
            .collect::<Vec<_>>()
            .join("")
        }
    }
}
David McGillicuddy
@djmcgill
May 13 2017 21:04
To do it "functionally" with a fold without mutation is a different question. You'd want some kind of group function that splits chars into blocks of the same char.
red75prime
@red75prime
May 13 2017 21:19
extern crate itertools;
use itertools::Itertools;

fn main() {
    let groups = "aabccccccdaasd".chars().group_by(|&c|c);
    let res: String = groups.into_iter().map(|(c, i)| {
        let len = i.count();
        if len == 1 {
            format!("{}", c)
        } else {
            format!("{}{}", len, c)
        }
    }).collect();

    println!("{:?}", res);
}
Fra ns
@snarf95_twitter
May 13 2017 21:21
That is some sweet code
red75prime
@red75prime
May 13 2017 21:26
Although it's less efficient. i.count() traverse group of chars second time.
Fra ns
@snarf95_twitter
May 13 2017 21:26
What's the type of i?
Can't you do is_empty or any?
red75prime
@red75prime
May 13 2017 21:29
it's itertools::structs::Group, essentially it's iterator
David McGillicuddy
@djmcgill
May 13 2017 21:33
Each i is your group of chars, i.e. aaa, bb or the like. So unfortunately you do need to count them.
Fra ns
@snarf95_twitter
May 13 2017 21:35
Hmm
David McGillicuddy
@djmcgill
May 13 2017 21:40
As a further optimisation to my last version with the loop, you could store the Vec<String> and keep the "last" element in a mut (char, u8) directly instead of storing the intermediate Vec<(char, u8)> and then converting to the Vec<String> in a second pass.
Fra ns
@snarf95_twitter
May 13 2017 21:42
Yeah I would prefer to stick with higher level functions but apparently rle is making it difficult. Would a peekable iterator help?
Denis Lisov
@tanriol
May 13 2017 21:48
@red75prime Are you sure i.count() traverses them the second time and not the first?
David McGillicuddy
@djmcgill
May 13 2017 21:49
I mean if you really want to do things purely you could try the last of the solutions here: https://wiki.haskell.org/99_questions/Solutions/10
Fra ns
@snarf95_twitter
May 13 2017 21:51
Thx and yeah you might be right about count
David McGillicuddy
@djmcgill
May 13 2017 21:52
Where instead of having acc be mutable and you append to it, you create it by chaining closures. (I think).
But you have two options: a super nice solution that might be slower (using group_by) or a manual and mutable solution that will probably be faster.
It might get optimised out anyway, unless this was a performance bottleneck I'd always go with @red75prime 's solution
Fra ns
@snarf95_twitter
May 13 2017 21:56
Thx I'm actually just trying to learn rust through exercism.io
David McGillicuddy
@djmcgill
May 13 2017 21:57
Sure, but it's worth thinking about the speed/clarity (maintainability) trade-off.
Fra ns
@snarf95_twitter
May 13 2017 22:01
Absolutely but I think you can produce some really nice code using higher order functions. I'm coming from a c# background and maintainability is everything.
If this was for production, you'd probably make a run length iterator?
Using lower level code
Denis Lisov
@tanriol
May 13 2017 22:03
@snarf95_twitter Note that higher order functions are not always a win in maintainability, and a concise loop may be much more readable sometimes...
David McGillicuddy
@djmcgill
May 13 2017 22:09
I think that the maintainability might not be too bad if you split the logic so that you had the loop be its own function:
fn encode(input: &str) -> Vec<(char, u8)>
But you'd still need a reason to do that over group_by IMO.