These are chat archives for rust-lang/rust

22nd
Feb 2019
Michal 'vorner' Vaner
@vorner
Feb 22 08:12
Didn't it even produce a warning that it doesn't know the key?
Kelly Thomas Kline
@kellytk
Feb 22 08:32
How can the error on line 5 of https://ghostbin.com/paste/7bt68 be solved?
Denis Lisov
@tanriol
Feb 22 09:07
Maybe use some internal method that takes a reference to self.groupusers instead of self?
i somehow dont get the differences between procedural function-like macros and delcarative macros
Michal 'vorner' Vaner
@vorner
Feb 22 09:14
They are the same if you use them. You just create them in a very different way.
thojest
@thojest
Feb 22 09:14
so the first is handling token streams and the latter one is about matching patterns?
Kelly Thomas Kline
@kellytk
Feb 22 09:15
@tanriol Would you show me an example of your idea?
Michal 'vorner' Vaner
@vorner
Feb 22 09:16
Declarative macros (the ones you create with macro_rules) are basically a match-and-replace template. The procedural ones are basically that you run arbitrary code. The code gets some code and produces a different code. But you can (and have to) do all the stuff manually (with some use of libraries).
The procedural ones are much more powerful. But also much more work.
thojest
@thojest
Feb 22 09:16
@vorner ahhh ok :) thx for the quick input
Michal 'vorner' Vaner
@vorner
Feb 22 09:18
The basic takeaway is, you use macro_rules for day to day development, if you find yourself repeating/copy-pasting too much code but can't make it line up with types and traits. You go all the way to procedural macros when writing fancy libraries like serde (derive style procedural macro) or testing frameworks. It's probably not worth to just save some lines of copy-pasted code.
thojest
@thojest
Feb 22 09:25
@vorner yepp I need it to provide some default implementation for instantiating randomized structs
Kelly Thomas Kline
@kellytk
Feb 22 10:02
@tanriol I've got it, thank you
thojest
@thojest
Feb 22 10:12
i recently compiled a crate depending on another crate without specifying extern crate foo; i only needed to specify the dependency in the cargo.toml
and then could use foo::bar;
is this new?
Tim Vermeulen
@timvermeulen
Feb 22 10:19
yeah, it’s part of the 2018 edition
octave99
@octave99
Feb 22 15:23
I have implemented Read trait like below:
impl Read for Inner {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = self.buf.len();
    buf[0..len].copy_from_slice(&self.buf);
    Ok(len)
  }
}
Its working but involves a copy, could there be a way to avoid it? If I assign slice directly, I get lifetime error, if I add lifetime specifier obviously it doesn't comply with trait requirement. Wondering if above is the only way.
Denis Lisov
@tanriol
Feb 22 15:28
There are a few problems with the code above. First, what if buf is shorter than self.buf?
Second, the same data can be read from it multiple times, which is usually not what you want.
But, answering your question, no, you cannot get rid of this copy.
octave99
@octave99
Feb 22 15:37
@tanriol How do I address the problem you have mentioned? I faced the length issue but could not think of that either so had to rely on fixed buffer size.
Denis Lisov
@tanriol
Feb 22 15:38
What's the type of self.buf?
Assuming it's a Vec<u8>, I'd go with
impl Read for Inner {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = min(self.buf.len(), buf.len());
    buf[0..len].copy_from_slice(&self.buf[0..len]);
    self.buf.drain(0..len);
    Ok(len)
  }
}
octave99
@octave99
Feb 22 15:48
Thanks.
Denis Lisov
@tanriol
Feb 22 15:55
Depending on your use case, I'd also really think whether Vec is an adequate storage or whether something different should be used instead :-)
octave99
@octave99
Feb 22 15:56
@tanriol I Am using BytesMut from bytes
Its a learning project to some network data
tokio::reactor::PollEvented2 requires Read to be implemented, so was trying to see if copies can be avoid at places
Ingvar Stepanyan
@RReverser
Feb 22 16:56
oops, no, I confused with something else
Félix Fischer
@felix91gr
Feb 22 18:27
Question: do nested functions capture anything from their surroundings?
It seems to me that they're treated like normal functions, except in the fact that they can only be reached from that inner scope
Ingvar Stepanyan
@RReverser
Feb 22 18:41
That's right
They're not closures, just nested functions.
Félix Fischer
@felix91gr
Feb 22 19:13
Oh, awesome
That makes life that much easier
:)
Thank you
Ichoran
@Ichoran
Feb 22 19:16

It's possibly because it's too awkward to deal with lifetimes of compiler-generated function arguments. In a GCed language like Scala you can write

def foo(n: Int): List[String] = {
  val x = List("salmon")
  def bar(i: Int) = List(i.toString) ++ x
  bar(n+1)
}

and you never have to worry about who is cleaning up all those lists and strings (except when you're hit by GC pauses...), so you don't care that add is actually add(i: Int, foo$x: List[String]) or somesuch in bytecode, and that in Rust notation it would be &List<String> (i.e. a borrow).

With Rust, capturing involves a choice about moving vs borrowing vs copying, and isolating those concerns to one place (closures) is probably best for everyone's sanity. The canonical port of the above code to Rust would probably be something like:

fn foo(n: i32) -> Vec<String> {
    let x = vec!["salmon".to_string()];
    let bar = |i: i32| { 
        let mut y = vec![i.to_string()];
        y.extend(x);
        y
    };
    bar(n+1)
}
Importantly here, Rust does the extra work in the closure to figure out what type of move or borrow is needed! If you just try the function version and fill in a second arg as if you were a compiler "capturing" a local variable by passing in, you'd probably write something like
fn foo(n: i32) -> Vec<String> {
    let x = vec!["salmon".to_string()];
    fn bar(i: i32, v: &Vec<String>) -> Vec<String> { 
        let mut y = vec![i.to_string()];
        y.extend(*v);
        y
    };
    bar(n+1, &x)
}
only to be admonished with
error[E0507]: cannot move out of borrowed content
 --> src/main.rs:5:18
  |
5 |         y.extend(*v);
  |                  ^^ cannot move out of borrowed content
So theoretically, yes, the Rust compiler could do all the analysis for nested functions as if they were closures and adapt the arguments and everything, but sometimes keeping it simple is better.
Ichoran
@Ichoran
Feb 22 19:31
(note--changed add to bar in the Scala code but forgot to update the description)
tsoernes
@tsoernes
Feb 22 19:49
Given that I have a String, and the byte-index of a 1-byte character, is there a way to swap it out (replace it) with another 1-byte character? Safely, if possible, but it must be done without copying or validity-checking the entire string.
Ingvar Stepanyan
@RReverser
Feb 22 19:53
The easiest is probably to use as_bytes_mut view
Since you are interested in a byte replacement anyway
tsoernes
@tsoernes
Feb 22 19:56
also, is is_char_boundary O(n)?
Ingvar Stepanyan
@RReverser
Feb 22 19:56
no, O(1)
tsoernes
@tsoernes
Feb 22 20:07
wouldn't it be theoretically possible to do safe 1-byte character replacements in constant time? Step 1: Check that byte index contains ASCII; Step 2: Check that given byte is valid ASCII
Ingvar Stepanyan
@RReverser
Feb 22 20:07
But what I suggested is safe...

The easiest is probably to use as_bytes_mut view

This

So, since you wanted one-byte character replacement and you have a byte index, you can do just that.
tsoernes
@tsoernes
Feb 22 20:09
@RReverser pub unsafe fn as_bytes_mut according to docs https://doc.rust-lang.org/std/primitive.str.html#method.as_bytes_mut
Ingvar Stepanyan
@RReverser
Feb 22 20:09
Ahh wait yeah
Right, so the reason it's marked as unsafe is because you can break UTF-8 if not careful
Which is fair enough, and, as you said, just means that you need to do your own checks
tsoernes
@tsoernes
Feb 22 20:11
yeah, got it.
Denis Lisov
@tanriol
Feb 22 20:20
Actually these workarounds are not required...
String::replace_range delegates to Vec::splice, which for an equal length replacement does not touch the tail and is O(1) wrt the length of the String.
Ingvar Stepanyan
@RReverser
Feb 22 20:37
As far as I understand from Vec::splice description, that's not technically guaranteed but rather current implementation detail?
I mean, it's nice that it's safe, but if the goal is guaranteed in-place replacement without reallocation, then might be more reliable to use the bytes view
Denis Lisov
@tanriol
Feb 22 20:40
Note 4 seems to be off-by-one about this :-)
octave99
@octave99
Feb 22 20:54
#[derive(Debug)]
struct Dog {
  name: String,
}

struct Animal<T> {
  inner: T,
}

impl<T> Animal<T> {
  fn new(inner: T) -> Self {
    Animal { inner }
  }
}

impl<Dog> Animal<Dog> {
  fn greet(&self) {
    print!("Dog name {:?}", self.inner.name);
  }
}
Above shows error " error[E0609]: no field 'name' on type 'Dog'
Trying to understand what is wrong in above code. Logically looks ok and even error shows the right type but slips on the field name
Ingvar Stepanyan
@RReverser
Feb 22 20:59
impl<Dog> is the problem
it's essentially same as impl<T>, but binding name Dog instead of T
you probably wanted just impl there
octave99
@octave99
Feb 22 21:00
aaha. Got it. Dog has been considered same as T
impl Animal<Dog> {
  fn greet(&self) {
    print!("Dog name {:?}", self.inner.name);
  }
}
This was it.
@RReverser Thanks.