These are chat archives for rust-lang/rust

15th
Nov 2016
Pavel Meledin
@btbvoy
Nov 15 2016 10:35

Question about how to think about Enum data type and just struct: Let’s assume that there is a piece of code in language which has traditional OOP. There is a need to have an array of some objects which have to be processed in a bulk. So let’s assume that all items in array have to be the same type. So there could be base class which is abstract (or might be a trait) and other child classes which extends base abstract class and contains specific for child classes’ fields. Taking an example in Scala it would look like this:

trait Fruit
case object Apple extends Fruit
case object Orange extends Fruit
case object Plum extends Fruit

case class GlassOfJuice(fruits: Set[Fruit])
// ...

val fruits = Seq(Apple, Orange, Plum)

def squeezer(fruits: Seq[Fruit]): GlassOfJuice = 
fruits.foldLeft(GlassOfJuice(Set.empty))((glass, fruit) => glass.copy(fruits = glass.fruits + fruit))

How similar code might look like in rust? Should Fruit and all child be a enum data type? Or in case of usage struct data type for it. How squeezerfunction would look like since structs can’t extends other structs.

Sebastian Blei
@iamsebastian
Nov 15 2016 10:46
Why should squeezer return GlassOfJuice with a set of fruits, while the class only contains a set of fruits?
Means, the initialization of the GlassOfJuice could take the fruits and set it as itselfs only property.
Pavel Meledin
@btbvoy
Nov 15 2016 10:52
well, propbably a bad example :-) I just wanted to simplify things for the example. I’m actually interesting in how the same code could be expressed in rust if not take into account that GlassOfJuice could be simle initiated like this:
GlassOfJiuce(fruits.toSet)
Maybe like this.
Pavel Meledin
@btbvoy
Nov 15 2016 10:55
aha, I see. So enum is the way to go in such example
Sebastian Blei
@iamsebastian
Nov 15 2016 10:56
I'm sure, this will depend on your problem.
Jonas Platte
@jplatte
Nov 15 2016 10:56
@btbvoy There is no one way to go about this. Traits seem like a reasonable solution as well in this example.
Sebastian Blei
@iamsebastian
Nov 15 2016 10:57
Yeah, for sure.
Jonas Platte
@jplatte
Nov 15 2016 10:58
This question very much reminds me of the RustConf talk without_boats gave: https://www.youtube.com/watch?v=erJdCIti_O8&list=PLE7tQUdRKcybLShxegjn0xyTTDJeYwEkI&index=8
Sebastian Blei
@iamsebastian
Nov 15 2016 10:59
I should watch it. Later. Otherwise, I will stuck on conf videos the whole day. :shipit:
Pavel Meledin
@btbvoy
Nov 15 2016 11:04
originally I’m trying to implement an application using CQRS Event Sourcing. In my original use case I have a list of Commands (which in my example - represented as Fruits) and a bulk of commands are translated into a sequence of events. So I started implementation just with structs but later on I understand if I want to have separated handler of commands and I want to process them in bulk - it need to have base type for all of them or imlement trait for them (but the idea with trait doesn’t look nice since it’s only tagging / putting a label on command in order to sutisfy compiler’s requirements and there is no any method on a command which is required for now). And I re-checked docs again and found an enum data type and was in doubts which way to go :-) and yes, I agree in software there is “it depends” :-)
@iamsebastian thanks for giving an example :-) I’ll give it a try
@jplatte thanks for the link to the talk, following an @iamsebastian I’ll take a look later a bit
Jonas Platte
@jplatte
Nov 15 2016 11:06
Okay, don't expect a clear answer to your question from the talk though :D
The main message I got from it is that it's still an open question which solution would be idiomatic for rust code facing this kind of question. But of course it's an interesting talk, and you should still watch it :)
Sebastian Blei
@iamsebastian
Nov 15 2016 11:08
You're welcome, @btbvoy
Nehal Hasnayeen
@Hasnayeen
Nov 15 2016 13:04
anybody use atom? i'm facing a problem with rust-linter package
Sebastian Blei
@iamsebastian
Nov 15 2016 13:05
Yeah, but just on the small MacBook for travel and quick read around.
Vim on the real work station.
Nehal Hasnayeen
@Hasnayeen
Nov 15 2016 13:07
i uninstalled previous rust version then installed the latest version using rustup, now rust-linter gives error :worried:
Sebastian Blei
@iamsebastian
Nov 15 2016 13:08
Well sorry, but I don't think I can help you with this. No MacBook here atm. :partly_sunny:
Pavel Meledin
@btbvoy
Nov 15 2016 13:09
@jplatte :-) just watched this talk. You are right indeed - there is no clear answer for such kind of questions
anyway that we nice talk :-)
Pavel Meledin
@btbvoy
Nov 15 2016 13:34
oops, typo: was nice talk*
Christopher Andrews
@CryptArchy
Nov 15 2016 20:35
I am, like, absolutely stuck on how to handle a lifetime borrow issue. Is it acceptable for me to post a short snippet that is causing the issue in here and ask for help?
mnivoliez
@mnivoliez
Nov 15 2016 20:44
Hello everyone. I got a question. When you use an extern crate. should you signal it only in main.rs? or in every files that use it?
Christopher Andrews
@CryptArchy
Nov 15 2016 20:47
I only put extern crate in the main.rs file.
You do need to use in every file/module that needs it. extern exposes the top-level symbol though.
So like extern crate chrono; doesn't require use chrono; in the same mod/file, but you will need use chrono; in other files. (You may also want to do something like use chrono::*; to bring symbols into scope unqualified.
Jonas Platte
@jplatte
Nov 15 2016 21:10
@CryptArchy If it's only a few lines, paste it here as a code block. Otherwise I'd say linking to it would be better.
If you scroll up a bit you'll see it's not uncommon to paste code here btw ;)
Christopher Andrews
@CryptArchy
Nov 15 2016 21:11
Sure, the problematic area is pretty small, code block should be fine.
fn start_kafka(tx: Sender<Message>) {
    let mut consumer = Consumer::from_hosts(vec!["example.com".to_owned()]); //... some other config omitted

    loop {
        for ms in consumer.poll().unwrap().iter() {
            for m in ms.messages() {
                tx.send(m);
            }
            consumer.consume_messageset(ms);
        }
        consumer.commit_consumed().unwrap();
    }
}
So, the reported problem is that the anonymous value of consumer.poll().unwrap() doesn't live long enough. But the actual problem is that I'm passing m (the Message) into tx a Sender<Message> type from the std::mpsc lib
I don't know how to fix this though. Conceptually, I think I get it. The channel is holding the value, so it can't be destroyed (which it will be at the end of the loop scope).
Jonas Platte
@jplatte
Nov 15 2016 21:15
I'll try to reproduce it in my playground dir... Sender and Consumer are from std::sync::mpsc, I assume? What's message?
Christopher Andrews
@CryptArchy
Nov 15 2016 21:15

The Message type itself looks like this: (from https://spicavigo.github.io/kafka-rust/kafka/consumer/struct.Message.html)

pub struct Message<'a> {
    pub offset: i64,
    pub key: &'a [u8],
    pub value: &'a [u8],
}

It's not marked as Clone so I can't copy the message directly. I've tried copying the values off of it but my own external clone method inherits the 'a lifetime from it, so the copy is still bound to the same lifespan.

Jonas Platte
@jplatte
Nov 15 2016 21:15
Ah ^^
Oh wait, Consumer isn't in std::sync::mpsc
But I think I should be able to drop in kafka as a dependency
Christopher Andrews
@CryptArchy
Nov 15 2016 21:16
No, Consumer is from the rust-kafka crate as well. That <'a> lifetime from the Message propogates all the way up to the poll method
I'm using kafka = "0.5" in my dependencies
Jonas Platte
@jplatte
Nov 15 2016 21:18
Hmmm, I used cargo add (from cargo-edit) and it added 0.5.0, so that seems to be the latest.
Christopher Andrews
@CryptArchy
Nov 15 2016 21:18
The minimal code for making a consumer that would likely build (though not run I'm guessing) would look like
let mut consumer = Consumer::from_hosts(vec!["example.com:9092".to_owned()])
        .with_topic_partitions("test".to_owned(), &[0])
        .with_fallback_offset(FetchOffset::Earliest)
        .with_group("mygroup".to_owned())
        .with_offset_storage(GroupOffsetStorage::Kafka)
        .create()
        .unwrap();
Jonas Platte
@jplatte
Nov 15 2016 21:18
I'm getting different errors though..
Christopher Andrews
@CryptArchy
Nov 15 2016 21:19
Well, maybe not "minimal" but close enough.
Jonas Platte
@jplatte
Nov 15 2016 21:19
error: no method named `poll` found for type `kafka::consumer::Builder` in the current scope
  --> src/main.rs:10:28
   |
10 |         for ms in consumer.poll().unwrap().iter() {
   |                            ^^^^

error: no method named `consume_messageset` found for type `kafka::consumer::Builder` in the current scope
  --> src/main.rs:14:22
   |
14 |             consumer.consume_messageset(ms);
   |                      ^^^^^^^^^^^^^^^^^^

error: no method named `commit_consumed` found for type `kafka::consumer::Builder` in the current scope
  --> src/main.rs:16:18
   |
16 |         consumer.commit_consumed().unwrap();
   |                  ^^^^^^^^^^^^^^^
That is what I get for your code plus
extern crate kafka;

use std::sync::mpsc::Sender;
use kafka::consumer::{Consumer, Message};
Christopher Andrews
@CryptArchy
Nov 15 2016 21:19
Replace the consumer binding with the code I just posted.
Jonas Platte
@jplatte
Nov 15 2016 21:19
Okay
Christopher Andrews
@CryptArchy
Nov 15 2016 21:19
I had elided the critical "create().unwrap()" bit that gives you an actual consumer and not a builder
I believe my usings are like:
use kafka::consumer::{Consumer, FetchOffset, GroupOffsetStorage};
use kafka::client::fetch::Message;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
Jonas Platte
@jplatte
Nov 15 2016 21:20
still getting a different error interestingly:
error[E0308]: mismatched types
  --> src/main.rs:19:25
   |
19 |                 tx.send(m);
   |                         ^ expected struct `kafka::consumer::Message`, found reference
   |
   = note: expected type `kafka::consumer::Message<'_>`
   = note:    found type `&kafka::consumer::Message<'_>`
I'll check if this is a compiler branch inconsistency...
Christopher Andrews
@CryptArchy
Nov 15 2016 21:21
Ah, no I think it's just leftover from experiments I was doing. Sorry about that, change the signature to be fn start_kafka(tx: Sender<Message>) {
Jonas Platte
@jplatte
Nov 15 2016 21:21
Okay, no, would have been weird too
that's how it looks..
I'll change it to send(*m) and see if that works
Christopher Andrews
@CryptArchy
Nov 15 2016 21:23
It'll give you a "moving out of borrowed context" error
I'm sorry, the opposite of what I just said, change the signature to be: fn start_kafka(tx: Sender<&Message>) {
Jonas Platte
@jplatte
Nov 15 2016 21:24
Hah, okay
Christopher Andrews
@CryptArchy
Nov 15 2016 21:24
I was trying to use a clone method that would take the &Message and copy the values into a new Message so that the Sender would own it (didn't work)
Jonas Platte
@jplatte
Nov 15 2016 21:24
ahh, yeah okay, now I see the error you were talking about
Christopher Andrews
@CryptArchy
Nov 15 2016 21:25
So it complains about the poll line but if you comment out the tx.send(m) it will compile so the source of the problem is trying to hold onto that m value which is then just propagating back up.
Jonas Platte
@jplatte
Nov 15 2016 21:40
Hm, I think I lack the knowledge about the context and what exactly this kafka library does to help. Maybe I can have a closer look tomorrow, if nobody else figures this out until then.
You should probably ask on the IRC channel too if you haven't done that yet.
There are more active people there