These are chat archives for rust-lang/rust

31st
Dec 2017
Murali
@mmrath
Dec 31 2017 00:36
@o0Ignition0o Thank you. I think a Vec would be good enough got me.
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 01:14
:+1:
Restioson
@Restioson
Dec 31 2017 09:12
So i'm sort of 'simulating' inheritance (please don't shout at me) with inherent impl's on traits
but it appears that none of the methods are visible?
they are all public, as are the structs and the trait
for instance
/// A PS2 device
pub trait Device {
    fn port(&self) -> DevicePort;
}

impl Device {
    pub fn enable(&mut self) -> Result<(), Ps2Error> {
        let cmd = if self.port() == DevicePort::One {
            ControllerCommand::EnablePort1
        } else {
            ControllerCommand::EnablePort2
        };
        self.send(cmd)
    }
    // ...
}

pub struct Keyboard {
    port: DevicePort
}

impl Device for Keyboard {
    fn port(&self) -> DevicePort {
        self.port
    }
}
now, if I try to use enable on keyboard
error[E0599]: no method named `enable` found for type `&'a mut drivers::ps2::device::Keyboard` in the current scope
   --> src/drivers/keyboard/mod.rs:229:21
    |
229 |         self.device.enable()?;
    |                     ^^^^^^
    |
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `enable`, perhaps you need to implement it:
            candidate #1: `drivers::keyboard::Keyboard`
(the recommended trait comes from a completely different module)
Restioson
@Restioson
Dec 31 2017 09:43
wow i'm dumb
I read the wrong path for the error...
Forgot to use...
Restioson
@Restioson
Dec 31 2017 09:50
huh ok apparently rust thinks it is private, even though I pub use self::mod::*; in another mod where i'm trying to import it from
I can access everything else in that module :(
grr, I added to test a pub trait FakeDevice and that works, just not the actual trait :(
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 09:58
Hey :) could you please put it in a playpen ? I'm a rookie but I might produce rubber duck debugging :)
Restioson
@Restioson
Dec 31 2017 09:58
The playpen works, which is even more confusing
let me try make it break
Well, I got it to exhibit a similar error
so confused rn, any help appreciated
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 10:10
I've been able to reproduce
I don't really understand this part :
mod device { pub trait Device { fn handshake(&self); } impl Device { pub fn greet(&self) { self.handshake(); println!("Hello!"); } }
AFAIK a trait is a set of functions you want to see implemented for any class which implement the trait
hence "trait Device" and "impl Device for MyAwesomeExtendingClass"
and impl here would implement each method defined in the trait
Restioson
@Restioson
Dec 31 2017 10:12
impl Device adds inherent methods to the trait
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 10:18
I've used impl for Structs adding inherent methods, but not for traits
since a trait is an interface, it would seem more explicit to define all methods first, and then eventually add impl Device for () to specify a default implementation
Restioson
@Restioson
Dec 31 2017 10:20
i think you mean impl<T: Device> T {}
But inherent methods are for that, aren't they?
first time using them
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 10:20
though i'm too junior to be sure
I'll write a playpen to express what i mean, wait :)
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 10:31
I think what you're trying to achieve (default trait implementation) is what is happening when we let our structs #[derive(Debug)] or display or serialize / deserialize
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 10:40
https://github.com/rust-lang/rust/blob/master/src/libcore/any.rs#L123 here s an implementation for the "Any" type
Doing this doesn't feel right at all though
Restioson
@Restioson
Dec 31 2017 10:40
I'm not trying to defaultly impl
Im trying to add inherent methods
red75prime
@red75prime
Dec 31 2017 11:03
@Restioson impl Device where Device is a trait means "We are implementing inherent methods for the trait object."
Restioson
@Restioson
Dec 31 2017 11:03
For only the trait object?
I want ideally for trait object and implementeds
Restioson
@Restioson
Dec 31 2017 11:04
rip
macro magic time
red75prime
@red75prime
Dec 31 2017 11:04
You can call those methods using UFCS
and implicit conversion of reference to implementer to reference to trait object
Restioson
@Restioson
Dec 31 2017 11:07
hm :/
oh
i guess i could make them default and not override
red75prime
@red75prime
Dec 31 2017 11:09
Explicit conversion will do too. (&y as &Device).greet()
NicolasVidal
@NicolasVidal
Dec 31 2017 11:10
Hello there, I would like to confirm something regarding maccro usage ...
let's say I'm writing a small lib in which a function will create an array of unknown size at lib compile time, but the size will be known for a user using the lib. If I do not want to use a Vec or anything heap allocated, is replacing the func with a maccro the only way to perform the trick ?
Aleksey Kladov
@matklad
Dec 31 2017 11:11
@NicolasVidal I think the user can parametrize the function with array
Restioson
@Restioson
Dec 31 2017 11:12
You need const generics
Aleksey Kladov
@matklad
Dec 31 2017 11:12
like foo::<[i32; 8]>().
Restioson
@Restioson
Dec 31 2017 11:12
i hackily did it with slices
NicolasVidal
@NicolasVidal
Dec 31 2017 11:12
and then I just use T() ?
Aleksey Kladov
@matklad
Dec 31 2017 11:12
@Restioson not really, you can parametrize directly with array type, like ArrayVec does it.
NicolasVidal
@NicolasVidal
Dec 31 2017 11:13
does arrayvec alloc on heap or on stack ?
Aleksey Kladov
@matklad
Dec 31 2017 11:13
@NicolasVidal yep, but you'll probably need some trait bounds on T
Restioson
@Restioson
Dec 31 2017 11:13
yeah, but you cant make it of unknown size
NicolasVidal
@NicolasVidal
Dec 31 2017 11:13
like Sized and stuff ?
Aleksey Kladov
@matklad
Dec 31 2017 11:14
Here's the relevant bit from ArrayVec for parametrizing with "arbitrary" array: https://docs.rs/arrayvec/0.4.6/arrayvec/trait.Array.html
Just to make it clear, ArrayVec works by storing [T; N], is uses stack allocation.
NicolasVidal
@NicolasVidal
Dec 31 2017 11:15
ok perfect thanks @matklad :)
NicolasVidal
@NicolasVidal
Dec 31 2017 11:24
so its 'cleaner' to use an ArrayVec instead + generics func of a macro ?
Aleksey Kladov
@matklad
Dec 31 2017 11:29

@NicolasVidal I think it depends on your particular use case. Basically, the choices are:

1) Write a macro
2) Let the user allocate array on the stack and use a mut slice argument
3) Use ArrayVec directly as a stack-allocated container
4) Use the trait Array trick from ArrayVec to roll your own compile-time parametrization with an array
5) Wait for const generics :)

I think 2) 3) would be reasonable choices in a large proportion of use cases.
Restioson
@Restioson
Dec 31 2017 11:39
@matklad theres a fixed number of generics you can do with that
its only becausr they impl'd Array for [T; N] in that case so it accepted
so for 'true' generic arrays we need const generics aka dependent types
Aleksey Kladov
@matklad
Dec 31 2017 11:54
@Restioson that's true, but it also true that any compiling real world program is finite in size, and so uses only a finite number of types :)
That is, theoretical purity should not prevent one from building useful things with tools which already exist in the language
Restioson
@Restioson
Dec 31 2017 12:02
well
it doesnt hve 57 as Array for instance
we need dependent types tho
Is there a way I can stop something being implemented for someone else's type?
some trait requirement?
I guess there's no reason they would implement it...
Restioson
@Restioson
Dec 31 2017 12:15
@red75prime hm... so if that is only for the trait object, is there a way you can do it for trait object + implementors?
Don't wanna have to use ufcs
@o0Ignition0o in the end I fixed it by making the function take &mut (Device + 'a)
idk why it works but it does
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 12:20
@Restioson good to hear, could you please send me a playpen so I can try to figure it out ? ^^
Restioson
@Restioson
Dec 31 2017 12:20
sure
i had one somewhere...
Restioson
@Restioson
Dec 31 2017 12:28
huh, can't seem to get trait function call syntax from inside of trait
says Self isn't Sized... taking it by reference (it already is?) says it doesnt' implement Device (but it does, it is literally inside the device impl)
NicolasVidal
@NicolasVidal
Dec 31 2017 12:44
Thanks a lot @matklad and @Restioson for your insights, I'll let you know the chosen solution :)
Restioson
@Restioson
Dec 31 2017 12:53
well, mine wasn't really a solution, it was a "wait for it to be impl'd"
Otherwise slices
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 12:57
wow that s really verbose but it works, I don't get why the first playpen you send couldn't work
Restioson
@Restioson
Dec 31 2017 13:57
I'm trying to make helper methods for a trait that its impls can call
but alas can't have private (or even pub(self)/pub(...) trait methods)
Any suggestions?
Unfortunately, the helper methods need to call public methods of the trait too
Restioson
@Restioson
Dec 31 2017 14:03
I did it with trait TraitHelper and then pub_method_helpers for all the public methods it needed to use
Any alternate design ideas appreciated >.>
David Harvey-Macaulay
@alteous
Dec 31 2017 14:17
@Restioson If you have a 'base type' in your hierarchy you could do something like this: https://github.com/three-rs/three/pull/148/files#diff-04e488aeda6267c5492931d655b0a7aaR35
Restioson
@Restioson
Dec 31 2017 14:18
I need private trait items though
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 14:18
like protected ?
Denis Lisov
@tanriol
Dec 31 2017 14:19
Are all impls in the same crate or in different crates?
Restioson
@Restioson
Dec 31 2017 14:19
All in the same crate
Protected from which language tho
Java?
Flashbacks
rust-lang/rfcs#275
I'm gonna comment my usecase there
Denis Lisov
@tanriol
Dec 31 2017 14:19
Why not make them just free functions in a helper module?
Restioson
@Restioson
Dec 31 2017 14:20
That's... kinda suboptimal
then why even have impl's on trait
if I'm just gonna do it C-style anyway
It's not that I can't do it, it's that I cant do it well and nicely
Denis Lisov
@tanriol
Dec 31 2017 14:22
What did you mean by "pub_method_helpers for all the public methods it needed to use"?
Restioson
@Restioson
Dec 31 2017 14:22
leme show you
/// Helper trait for devices which allows sending commands to be private
trait DeviceHelper {
    fn state_helper(&self) -> Result<DeviceState, Ps2Error>;
    fn port_helper(&self) -> DevicePort;
and then
impl<T: Device> DeviceHelper for T {
    fn state_helper(&self) -> Result<DeviceState, Ps2Error> {
        self.state()
    }

    fn port_helper(&self) -> DevicePort {
        self.port()
    }
}
Jeremy Lempereur
@o0Ignition0o
Dec 31 2017 14:29
I can hardly think of a use case where an "interface" would have to specify inner workings of an "object" implementing the interface, so I guess I don't get why a trait would have to specify private functions (and defaults) :/
i mean, if it's in your trait, that means your clients will need to be aware of it, so it s supposed to be in your public api shouldnt it ?
you couldn't use polymorphism or do anything specific with what the trait provides you if it was private anyway could you ?
Denis Lisov
@tanriol
Dec 31 2017 14:31
@Restioson How about trait DeviceHelper: Device?
David Harvey-Macaulay
@alteous
Dec 31 2017 14:31
Would something like this work?
pub trait Public {
     fn public(&self);
}

trait Private: Public {
    fn private(&self) {
        self.public()
    }
}
Restioson
@Restioson
Dec 31 2017 14:31
That's exactly what I did
but it is suboptimal imo
David Harvey-Macaulay
@alteous
Dec 31 2017 14:32
Why?
Denis Lisov
@tanriol
Dec 31 2017 14:32
If the private trait requires the public one, you don't need helpers, do you?
Restioson
@Restioson
Dec 31 2017 14:32
@alteous @tanriol I did those things, but that is a messy solution IMO.
No
The Device trait requires the DeviceHelper trait
Since the Device trait's defaultedly implemented methods call the helper methods
let me trim it
Restioson
@Restioson
Dec 31 2017 14:45
Any ideas?
Denis Lisov
@tanriol
Dec 31 2017 14:49
You can split the helper definition and impl :-)
Restioson
@Restioson
Dec 31 2017 14:49
No reason to, is there?
ohh i do see, ill try that
still sort of a place where i'd love private trait item
Denis Lisov
@tanriol
Dec 31 2017 14:50
The impl has the T: Device bound, so it should be able to use the Device members
Restioson
@Restioson
Dec 31 2017 14:50
Yea
Restioson
@Restioson
Dec 31 2017 15:05
@tanriol nvm, that is illegal
warning: private trait `drivers::ps2::device::DeviceHelper` in public interface (error E0445)
   --> src/drivers/ps2/device/mod.rs:68:1
    |
68  | / pub trait Device: DeviceHelper {
69  | |     fn port(&self) -> DevicePort;
70  | | 
71  | |     /// Enables this device
...   |
157 | |     }
158 | | }
    | |_^
    |
    = note: #[warn(private_in_public)] on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
:(
Denis Lisov
@tanriol
Dec 31 2017 15:08
Missed this point... however, the DeviceHelper: Device variant should not trigger this error, IIUC.
Restioson
@Restioson
Dec 31 2017 15:08
unfortunately, Device methods need to call things from DeviceHelper
see the gist i sent (second)
Denis Lisov
@tanriol
Dec 31 2017 15:09
Would it work with impl<T: DeviceHelper> Device for T and using specialization if/when you need to override them?
Restioson
@Restioson
Dec 31 2017 15:10
Hm....
hmmmmmmmmmmmmmmm
Ehh
this whole approach is a bit ... off
XY problem
I want to add un-overridable methods to the trait
so I guess I could just impl<T: DeviceHelper> Device for T and not specialise
welp i just got an ICE
Let me report
wait sorry what
it disappears on playground
Restioson
@Restioson
Dec 31 2017 15:15
Lemme update
Restioson
@Restioson
Dec 31 2017 15:23
I feel like I'm going around this the wrong way
I basically want to have a 'base class/trait' for Device which then Keyboard and Mouse will implement, and also extend. I don't want or need for methods in Device to be overridable (except 1). Any ideas?
Denis Lisov
@tanriol
Dec 31 2017 15:32
Do you need the Device methods to be available on Keyboard/Mouse?
Restioson
@Restioson
Dec 31 2017 15:33
Yes.
Denis Lisov
@tanriol
Dec 31 2017 15:35
So you have struct Keyboard and struct Mouse -- or are these two traits too?
Restioson
@Restioson
Dec 31 2017 15:35
Those are structs
Denis Lisov
@tanriol
Dec 31 2017 15:45
And what's the problem with just implementing Device for them and extending with inherent methods on Keyboard/Mouse?
Restioson
@Restioson
Dec 31 2017 16:01
That's what I currently do, except that lets the impls of device methods be overriden
@tanriol sry just got back
Denis Lisov
@tanriol
Dec 31 2017 16:02
...lets the impls be overridden where?
Restioson
@Restioson
Dec 31 2017 16:02
By anyone implementing Device
because the implementations are the same for anything so they're more like inherent methods
but I can't do that since it's only for trait object
grrrrrrrrrr
Denis Lisov
@tanriol
Dec 31 2017 16:03
Which should have only two implementations mentioned above, yes?
Restioson
@Restioson
Dec 31 2017 16:03
Yes
well no
The impl would really basically be
impl Device for Keyboad {}
Denis Lisov
@tanriol
Dec 31 2017 16:06
Nothing else except Keyboard and Mouse should implement it?
Restioson
@Restioson
Dec 31 2017 16:13
No
i mean they can, but why
Denis Lisov
@tanriol
Dec 31 2017 16:17
So sounds like either (a) "but why" and you don't need to do anything, or (b) what you actually want is to ensure no one can implement this trait incorrectly. I'm pretty sure you can implement it for Keyboard and Mouse correctly without the compiler enforcing you don't override anything. What an I missing here?
Restioson
@Restioson
Dec 31 2017 16:20
No. There is nothing here to implement really -- all you gotta do is give it some member functions (what port its in) and then get its methods for free otherwise
Denis Lisov
@tanriol
Dec 31 2017 16:25

Ok, seems like I'm misunderstanding something.

I basically want to have a 'base class/trait' for Device which then Keyboard and Mouse will implement, and also extend. I don't want or need for methods in Device to be overridable (except 1).

Sounds like the trait Device already solves everything except "don't want... to be overridable". However, if you don't need to override them in the impls for Mouse and Keyboard, you just don't. Do you want the compiler to enforce this? Why exactly is one trait Device and inherent methods on Keyboard/Mouse not an acceptable solution?

Restioson
@Restioson
Dec 31 2017 16:25
true true
Then the issue is that I want to have a helper function just used from within Device's method impl's which is private
Restioson
@Restioson
Dec 31 2017 16:38
How does one debug/report an ICE one can't reproduce out of one's own code >.>
Denis Lisov
@tanriol
Dec 31 2017 16:41
You can probably use free functions or a helper trait... something like this
Restioson
@Restioson
Dec 31 2017 16:41
True
I feel like there's a better way though
just haunting me
Denis Lisov
@tanriol
Dec 31 2017 16:43
The one thing that feels strange to me is that you need to call helpers from public methods and the other way round. Are you sure the abstraction boundary is drawn correctly?
Restioson
@Restioson
Dec 31 2017 16:43
Hmmm
Well, the things I call from the helper methods are port -- get the port the PS2 device is in -- and state -- get the state it is in
i.e enabled or disabled
Restioson
@Restioson
Dec 31 2017 16:58
So i got myself a lovely ICE
error: internal compiler error: /checkout/src/librustc_const_eval/_match.rs:261: bad constructor ConstantValue(Const { ty: drivers::keyboard::Keycode, val: Aggregate(Struct([(inner, Const { ty: u8, val: Integral(U8(33)) })])) }) for adt drivers::keyboard::Keycode
However, i can't reproduce in playground
I don't know what's causing the error
I assumed it was something here:
/// Represents a Flower keycode
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Keycode {
    inner: u8
}

impl Keycode {
    /// Creates a key code from its inner value
    pub const fn from_val(val: u8) -> Self {
        Keycode {
            inner: val
        }
    }

    /// Gets the Flower keycode for a key based on its row and column.
    pub const fn from_row_col(row: u8, col: u8) -> Self {
        Keycode::from_val((col & 0x1F) | (row & 0x7) << 5)
    }
}
But apparently not since it compiles fine in playground
Denis Lisov
@tanriol
Dec 31 2017 17:01
Looks like #46114
Restioson
@Restioson
Dec 31 2017 17:06
ah, thanks
Restioson
@Restioson
Dec 31 2017 17:27
So, this is not allowed
match keycode_opt {
    Some(keycode) => Ok(keycode),
    None if !scancode.extended => Err(UnknownPlainScancode(scancode.code)),
    None if scancode.extended => Err(UnknownExtendedScancode(scancode.code)),
}
Apparently you need _ too
Denis Lisov
@tanriol
Dec 31 2017 17:29
Or drop the condition on the last case
Restioson
@Restioson
Dec 31 2017 17:29
true
but I prefer the semantics if having it in
i just added _ => unreachable!()
Denis Lisov
@tanriol
Dec 31 2017 17:30
Or match (keycode_opt, scancode.extended)
Restioson
@Restioson
Dec 31 2017 17:31
hrmr