These are chat archives for rust-lang/rust

26th
Jan 2018
Kelly Thomas Kline
@kellytk
Jan 26 2018 04:29
When implementing FromStr for a struct what should be provided for the Err associated type?
Zakarum
@omni-viral
Jan 26 2018 06:29
If you implement it for Foo than FooParseError
@kellytk
Kelly Thomas Kline
@kellytk
Jan 26 2018 06:31
@omni-viral type Err = FooParseError; produces the error "error[E0412]: cannot find type FooParseError in this scope"
Zakarum
@omni-viral
Jan 26 2018 06:36
Because you need to create it first
Kelly Thomas Kline
@kellytk
Jan 26 2018 06:39
@omni-viral Is that idiomatic Rust style, to create a set of custom error types for each struct?
Zakarum
@omni-viral
Jan 26 2018 06:53
For each different cause of error.
In your case it must be different cause. Unless it is actually one of existing errors.
Kelly Thomas Kline
@kellytk
Jan 26 2018 07:15
Thanks @omni-viral
Kelly Thomas Kline
@kellytk
Jan 26 2018 08:40
What is the cause of the type error beginning on line 56 at https://play.integer32.com/?gist=d9eea5b30d6fe2ddd556364d28c434c0&version=stable
Zakarum
@omni-viral
Jan 26 2018 08:41
Exactly what it says
Ok arm returns Input
Err arm returns ()
But types must be equal
Consider to replace println with panic
Kelly Thomas Kline
@kellytk
Jan 26 2018 08:42
How would the Err arm 'return' Input? Or is the point that it cannot, and therefore the program must terminate?
Zakarum
@omni-viral
Jan 26 2018 08:43
It cannot and so function must return earlier. One way to do so is terminate. The other way is return statement in Err arm
both panic! and return evaluates to ! which is special type that will typecheck with any other type
Kelly Thomas Kline
@kellytk
Jan 26 2018 08:45
I used continue and it compiled without error
Zakarum
@omni-viral
Jan 26 2018 08:45
That's another way. Also break will work too
they are similart to return for the typechecker
Kelly Thomas Kline
@kellytk
Jan 26 2018 08:47
Fascinating, thanks
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 08:48
Zakarum, return does not evaluate to ! yes?
Zakarum
@omni-viral
Jan 26 2018 08:48
let x = return (); what the type of x?
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 08:48
unit type
Zakarum
@omni-viral
Jan 26 2018 08:49
Sure?
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 08:49
hmm... let me see
never used return as an expression before though (:з」∠)
Zakarum
@omni-viral
Jan 26 2018 08:50
I'm sure you did but in more complex expressions
like match x { Err(err) => return err, Ok(x) => x, }
the error indicates x is () type no?
Zakarum
@omni-viral
Jan 26 2018 08:52
You didn't save it
You need to press Share again
(:з」∠) sorry
Zakarum
@omni-viral
Jan 26 2018 08:54
This is unexpected
Zakarum
@omni-viral
Jan 26 2018 08:55
While let x =&return () works as expected
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 08:56
i think a function like fn func() has unit return type to match the type of return expression, while things like panic! has ! to match the return type of any function, e.g. fn func() -> Anything
Zakarum
@omni-viral
Jan 26 2018 08:56
As @qthree 's example shows. return will produce whatever type you like
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 08:56
wow
Zakarum
@omni-viral
Jan 26 2018 08:57
@y-usuzumi Yes. And so return, break and continue
I think it just fallback to () because it can't put ! on the stack
Cause ! has no size
Patrick Elsen
@xfbs
Jan 26 2018 08:58
I think return always returns ()
Try this code:
fn main() {
    func();
}

fn func() -> i16 {
    let x: () = return 888;
}
Zakarum
@omni-viral
Jan 26 2018 08:58

Try this

let x: u32 = return ();

Patrick Elsen
@xfbs
Jan 26 2018 08:59
Okay, you're right, works equally well :)
Zakarum
@omni-viral
Jan 26 2018 08:59
That's the point of ! type :smile:
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 09:00
thank you. i learned something new :D
Kelly Thomas Kline
@kellytk
Jan 26 2018 09:00
Is ! like any from TypeScript?
Zakarum
@omni-viral
Jan 26 2018 09:00
No
! is uninhabited
You can't create an instance of !
It's like enum Void {}.
Kelly Thomas Kline
@kellytk
Jan 26 2018 09:01
Would you expand on "! which is special type that will typecheck with any other type"?
Patrick Elsen
@xfbs
Jan 26 2018 09:01
How would I get this to work then tho:
fn other() -> ! {
}

fn func() -> i16 {
    let x: u32 = other();
}
Zakarum
@omni-viral
Jan 26 2018 09:01
@xfbs other should never return
! return type means the function never returns
Similar to Result<T, !> means function never fails
red75prime
@red75prime
Jan 26 2018 09:02
fn other() -> ! { panic!("bottom"); }
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 09:02
@xfbs or an infinite loop
Patrick Elsen
@xfbs
Jan 26 2018 09:03
Well, if you pop unreachable!() into other() it'll compile, but you'll get an interesting warning about it having entered unreachable code :)
Zakarum
@omni-viral
Jan 26 2018 09:03
@kellytk I see it as syntactic sugar.
You always can do match x {} when x: !
match x {} has no arms
So it can be any type
And it ok for match to have no arms. Because ! has no instances
And it ok for match to have no arms. Because ! has no values
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 09:07
@omni-viral what's the difference between instances and values?
Zakarum
@omni-viral
Jan 26 2018 09:08
instance of type Foo is Foo {}
values of type u32 are numbers from 0 to 2^32 - 1
values of enum Enum { Foo, Bar, Baz } are Foo, Bar and Baz
Kelly Thomas Kline
@kellytk
Jan 26 2018 09:09
Instances are values of complex types and values are valid simple types, is that correct @omni-viral?
Zakarum
@omni-viral
Jan 26 2018 09:10
No, I mean that 3 is a value of u32 but if you have let x = 3; let y = 3; those x and y are two different instances that have same value
Kelly Thomas Kline
@kellytk
Jan 26 2018 09:10
Oh
Zakarum
@omni-viral
Jan 26 2018 09:11
So consider enum Void {}. It has no values
Hence you can't create an instance of type Void
So if you have instance of type Void in your code. Like let x: Void = ... you know that this code is statically unreachable. Unless someone did transmute or something alike.
qthree
@qthree
Jan 26 2018 09:14
Unit type has only one value () but you can have as many instances of it as you like.
Zakarum
@omni-viral
Jan 26 2018 09:15
@qthree is better than me at explainging stuff
qthree
@qthree
Jan 26 2018 09:16
And singleton types can have different inner states (values), but can only be instanced once per type.
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:01
wow
you guys are awesome
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:03
Is ++ supported for incrementing number types? It's not at https://doc.rust-lang.org/book/second-edition/appendix-02-operators.html so I suspect not however I'd rather not assume
Zakarum
@omni-viral
Jan 26 2018 10:03
No. There is no ++
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:03
Thanks, I'll use x += 1
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:11
@omni-viral is there any Haskell equivalent to !. I think it's just an arbitrary type variable
Tom Cumming
@tomcumming
Jan 26 2018 10:11
data Void
aka a type with no constructors
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:13
but in Rust you can use ! type as any type
Tom Cumming
@tomcumming
Jan 26 2018 10:13
yeah, bottom
sorry i think i misunderstood
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:14
in haskell bottom is not type Void, undefined :: a
Tom Cumming
@tomcumming
Jan 26 2018 10:16
everything is a supertype of ! in rust, right?
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:17
well this does not work: let x = 3 + panic!("Hello");,
or let x = 3 + loop {};
Michal 'vorner' Vaner
@vorner
Jan 26 2018 10:18
Because the + is overloaded and unless you tell it the type of the right side, it can't choose the implementation.
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:19
i see
Michal 'vorner' Vaner
@vorner
Jan 26 2018 10:19
If you have add(a: i32, b: i32) and call it with add(3, panic!("Hello"));, it should work I think.
(I didn't try)
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:21
@vorner yes it worked as you expected
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:32
k i think ! in Rust is forall a. a in Haskell
Zakarum
@omni-viral
Jan 26 2018 10:32
Why not Haskell's ?
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:32
but Rust allows something like fn (a: !) -> ! while in Haskell it's not yet supported
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:33
Zakarum
@omni-viral
Jan 26 2018 10:33
@kellytk That's no how write for loops in rust
And v is &'static str, it doesn't implement AddAssign
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:36
@omni-viral sorry you beat me. i can't tell exactly what is a type
Zakarum
@omni-viral
Jan 26 2018 10:36
In haskell is called bottom
It isn't actually a type
Like ()
But in subtyping systems, the bottom type is the subtype of all types
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:39
() is a type with one value: ()
wikipedia says bottom type is also empty type. but Void is not a subtype of all types
Zakarum
@omni-viral
Jan 26 2018 10:41
Sorry for confusion.

Like ()

Means not what I was goind to say

Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:41
:D
Zakarum
@omni-viral
Jan 26 2018 10:42
Forgive me my bad english :smile:
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:43
you have been explaining stuff really clear
my english is bad too xD
Zakarum
@omni-viral
Jan 26 2018 10:43
Bottom can have different semantics.
In haskell it is uninhabinted (like void) but it is also subtype of all types
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:44
How should v on line 6 at https://play.integer32.com/?gist=4926edccdae6f866f0a53002d392c5ab&version=stable be declared to annotate it with the lifetime correctly?
Zakarum
@omni-viral
Jan 26 2018 10:44

From wikipedia:

The type Empty is not quite empty, as it contains non-terminating programs

That's pretty close definition of ! type.
@kellytk no way
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:47
indeed.
Zakarum
@omni-viral
Jan 26 2018 10:47
Your v has local lifetime.
It is destroyed at the end of function
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:47
How would I do what I want to do, which is to build and return (giving ownership) of a new string?
Zakarum
@omni-viral
Jan 26 2018 10:47
So you can't return reference to it
Return String
String owns string
while &str doesn't. It borrows.
Kelly Thomas Kline
@kellytk
Jan 26 2018 10:49
Thanks
Yukio Usuzumi
@y-usuzumi
Jan 26 2018 10:49
@omni-viral i need a bit of thinking. I still have a feeling i have misunderstood something
@omni-viral thanks a lot
Zakarum
@omni-viral
Jan 26 2018 10:54
@y-usuzumi Can't you write this forall a. (forall b. b) -> a in haskell?
It should be the same as fn (a: !) -> ! in rust
Tom Cumming
@tomcumming
Jan 26 2018 10:55
@omni-viral its an extension
Zakarum
@omni-viral
Jan 26 2018 10:55
ExistentialQuantification?
Zakarum
@omni-viral
Jan 26 2018 11:02
Hm. RankNTypes is enough
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:44

Hello. I'm observing something very strange. I'm trying to compare different ways to do network IO, for my crate corona. I wrote a benchmark that compares corona, plain tokio+futures and threads (starting a thread for each connection). Corona is the slowest, which is no surprise as I haven't started with any optimisations yet and it's additional layer. The threads are usually fastest ‒ which is a bit surprising, because I thought starting threads is expensive, but it seems the fact they can run in parallel on multi-core CPU compensates that. However, when I keep increasing the number of parallel connections, there's a huge jump somewhere between 150-160 connected clients.

This is if I run with 150:

test corona  ... bench:  15,543,695 ns/iter (+/- 1,349,120)
test futures ... bench:  13,147,925 ns/iter (+/- 965,723)
test threads ... bench:  12,879,193 ns/iter (+/- 315,977,471)

And this with 160:

test corona  ... bench:  16,514,686 ns/iter (+/- 1,744,063)
test futures ... bench:  14,279,801 ns/iter (+/- 1,682,019)
test threads ... bench: 623,363,124 ns/iter (+/- 1,012,012,305)

Increasing further makes the threads run much slower, so I lost patience with them.

Any idea what might be happening to them? I guess it's expected the threads go slower once there's too many of them, but this huge jump?

The code is here: https://github.com/vorner/corona/blob/master/benches/compare_methods.rs

Also, is there a trick how to run the benchmarks with different parameter (or multiple parameters) and get a graph?
Alkis Evlogimenos
@alkis
Jan 26 2018 20:46
@vorner did you try may as well? That would make a nice blog post :-)
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:47
I haven't tried may. I don't know how to fullfill its unsafe contract reliably O:-).
Alkis Evlogimenos
@alkis
Jan 26 2018 20:47
which part of it?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:49
„Access TLS in coroutine may trigger undefined behavior.“ A bunch of things I might want to call may access TLS under the hood. Like panic!. Or maybe stdio.
Also, it's not just TLS. The fact that the coroutine's stack can move between threads while the stack contains arbitrary non-Send things is just plain wrong.
I might try it for a benchmark some day, but I wanted the benchmark to simply make sure my own crate is not performance-terrible. The primary goal is not performance, but convenience ‒ but I don't want to be super-slow.
Alkis Evlogimenos
@alkis
Jan 26 2018 20:51
best convenience is with may or libfringe
except the latter does not work with windows
Steve Klabnik
@steveklabnik
Jan 26 2018 20:52
may also has TLS issues
it will also blow up if you do that stuff
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:52
However, I'd still like to know what the hell happens with the threads ‒ is it something the kernel does, or is it something rust does, or do I have some stupid bug in the code?
Steve Klabnik
@steveklabnik
Jan 26 2018 20:53
oh lol ignore me, that's literally waht you were talking about
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:53
@steveklabnik That's what I was saying there ↑. Corona (I think) shouldn't have these safety issues because it doesn't migrate coroutines.
Heh, yes :-)
Alkis Evlogimenos
@alkis
Jan 26 2018 20:53
are you running this on a multicore?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:53
(A coroutine always stays on the same thread)
Alkis Evlogimenos
@alkis
Jan 26 2018 20:53
then its no wonder threads go faster until you introduce too many context switches
Michal 'vorner' Vaner
@vorner
Jan 26 2018 20:54
Yes, 8-core AMD. It's kind of hard getting a single-core CPU these days.
Sure, but I'd expect the performance degradation of threads to happen gradually, not being 15% faster all the time, until somewhere between 150-160 threads and then bang, they get 30* slower at once.
Denis Lisov
@tanriol
Jan 26 2018 20:55
@vorner I've cloned your code and do see some weirdness (although different from your description)
Alkis Evlogimenos
@alkis
Jan 26 2018 20:55
futures don't do multi-core IO. I assume corona does the same.
maybe that is an artifact of the kernel scheduler
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:00
Yes, corona is single-threaded. It's just an attempt to work with tokio-core, but with less hassle than with all these future combinators. I guess once generators are stabilized, most of the things will be possible with them and there'll be little reason for corona (maybe for some special stuff, where stack-full coroutines and waiting for borrowed futures is needed).
@tanriol Did you try changing the PARALLEL constant? Or, what weirdness do you see?
Denis Lisov
@tanriol
Jan 26 2018 21:05
test threads ... bench: 9,033,313 ns/iter (+/- 202,346,734)
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:06
Like, the high amount of jitter?
I've noticed that too. And also when watching top, it seems there are long times when it does nothing. So it seems like most iterations are still fast, but from time to time it just locks up for a while.
Denis Lisov
@tanriol
Jan 26 2018 21:08
Yes, when jitter is 20 times the signal something's wrong...
Alkis Evlogimenos
@alkis
Jan 26 2018 21:08
kinda means the measurement is bogus :-p
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:10
@alkis That's why I'm trying to investigate it. If most iterations are fast, but it sometimes locks up but only for a while and then continues, it is fishy.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:10
what is an exchange? are you building some kind of trader?
what OS are you running this on?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:11
No, that's just sending one bufferful of data and then reading it back once it echoes.
Linux, 4.13.11.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:13
try to run the threads under pprof and vary PARALLELISM and try to understand what is causing the slowdown
sorry not pprof, perf
Peter Atashian
@retep998
Jan 26 2018 21:14
If you want user mode threads without TLS issues, at least on Windows you can use UMS
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:17
Yes, I know perf. I will try, but I don't expect much from it, because the problem seems the program just sleeps for a second from time to time, not to be burning CPU.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:18
if the CPU just sleeps you will see it in the instruction counts
if your program sleeps but the kernel scheduler goes bonkers the instruction counts will be still high
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:19
Hmm. Maybe I'll wait until that btrfs scrub finishes, or I'll get a lot of useless noise from it. Thanks for suggestions, I hoped someone might have seen such problem before… probably not, so I'll have to investigate.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:21
https://github.com/andikleen/pmu-tools mentions intel's topdown method implemented on top of linux perf
if that works for your CPU that would be the fastest way to dig in and figure out why things are different between 150 and 160 threads
Alkis Evlogimenos
@alkis
Jan 26 2018 21:39
@steveklabnik does libfringe have the same problems with TLS as may?
Steve Klabnik
@steveklabnik
Jan 26 2018 21:39
i don't believe so
but am not 100% sure tbh
if i were doing this, id use libfringe though
Alkis Evlogimenos
@alkis
Jan 26 2018 21:41
AFAIU libfringe is just like context-rs/genetor-rs which allows you to suspend and resume. so if you are to move libfringe generators across threads, TLS will break too.
but maybe I am missing something
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:41
It looks so to me too. It's a different level of abstraction.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:44
I saw a recent post on internals (or was it somewhere else?) asking for reducing TLS usage in std and making the I/O libraries coroutine friendly to allow more experimentation with different runtimes like may etc. I can't find it again though... does anyone remember this?
Steve Klabnik
@steveklabnik
Jan 26 2018 21:45
yeah it's not really possible without breaking changes
as far as i know
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:45
If you limit it in std, do you want to ask all the 3rd party crate authors to not use TLS too?
Alkis Evlogimenos
@alkis
Jan 26 2018 21:47
depends on the outcome of experimentation. noone knows how this will pan out. maybe we get a superb coro runtime implemented as a library and then 3rd party crates can have a feature for using either TLS or CTS locals where necessary
or maybe we can find some way to switch between the two without flags
but right not it is hard to experiment there is little exploration/progression
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:49
All of them? I mean, the TLS is a soundness issue.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:49
all the stackfull ones seem to have the TLS soundness issue
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:49
However, I don't see much problem with the fact the coroutines can't migrate. If you create a thread pool and spawn a coroutine round-robin on the threads and don't move them around, then you're fine.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:49
:-)
that's exactly the problem
there is enough evidence in research and implementations that points to work-stealing schedulers as the pinnacle of high performance :-)
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:50
First, the problem is not about being stack-full. And second, I was asking about all of the 3rd-party crates for whatever else, like your gui libraries, networking libraries, parsers… all these must not use TLS
Alkis Evlogimenos
@alkis
Jan 26 2018 21:51
without migration of coroutines work-stealing is impossible
they can use TLS or CLS
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:52
Yes, but you'd have to ask every crate author out there to update.
And it's not only TLS. There are other things that are not send.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:53
better done now when the language is young
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:53
Like a ZMQ socket.
It can't move between threads.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:53
why is that not send?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:53
Because the C library below it says so. Don't move between threads or you get segfaults.
GUI libraries sometimes have similar issues.
Alkis Evlogimenos
@alkis
Jan 26 2018 21:54
GUI libraries have bigger issues
they want all their code to run on the GUI thread
but that one is solvable: you can require that the coro moves to the GUI thread when it runs GUI code
so ZMQ doesn't move between theads presumable because of TLS. With enough perspiration this can solved as well :-) Either a rust impl of ZMQ or fixing ZMQ to be Send. In any case we are way ahead of the discussion. The point is to enable experimentation to find the best architecture/implementation for modern highly parallel CPUs.
Michal 'vorner' Vaner
@vorner
Jan 26 2018 21:59
Yes, but you can't say „I want to move things that are not Send from thread to thread“. That's against all the safety rules.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:00
Never said that :-)
You can easily say though: coros must be Send
so then you can't capture non-Send stuff in them
or you can say my runtime only works Send coros
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:00
How do you do it, in a function that stores whatever it likes on its stack?
Alkis Evlogimenos
@alkis
Jan 26 2018 22:02
this is something that needs some support from the compiler: need to be able to figure out that on suspension points there is nothing non-Send on the stack
its ok to have non-Send stuff that is ephemerally on the stack
so basically if you are thinking of Generators: all the state that is alive across suspension points must be Send or the Generator is not Send
but generator can call a function that puts a non-Send on its frame and then returns (there is no suspension there and the frame of the function is always poped)
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:03
That works for generators fine already. But if your function can have a suspension point in it and can be called by other functions, the functions above you could be storing the non-send stuff
It's (relatively) easy to say that the function you call is either Send or NoSuspension. But how can you check what functions are allowed to call you, all the way up to the top of the stack?
Alkis Evlogimenos
@alkis
Jan 26 2018 22:06
if the top level coro is NoSuspension then it is easy: this coro won't migrate from its thread because after it starts it does not relinguish the thread
if the top level is Send then everything that it calls must be Send or NoSuspension
(I think)
also I feel that some kind of NoSuspension marker is necessary to be able to compose coros together and get both things that returns series of values (generators) and async i/o as efficient as possible
Kelly Thomas Kline
@kellytk
Jan 26 2018 22:25
Where is :? defined, in the context of a format string's {} parameter syntax, if not at https://doc.rust-lang.org/std/fmt/ ?
Denis Lisov
@tanriol
Jan 26 2018 22:27
It's there, see formatters
Alkis Evlogimenos
@alkis
Jan 26 2018 22:30
@vorner am I right to think that not all uses of TLS are the same and one can make something Send even if it uses TLS?
Kelly Thomas Kline
@kellytk
Jan 26 2018 22:30
Oh, thanks @tanriol. I missed it as I was searching for the string :?
Why must fmt::Display be implemented on my custom error so I may print it with {}, when printing it with {:?} works by default?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:31
@alkis Huh, what? Send is for data… TLS can be accessed by a function. I don't see how it relates to each other.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:34
can't a closure be Send or not depending on what it captures?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:35
It is. But TLS is not captured by it. And I don't think a normal function even can talk about being or not Send.
Because the normal function doesn't contain any data.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:39
A normal function can't. I am not sure if such functions have a problem being called from different threads in the context of a coroutine that moves between threads. I can't think of an example that breaks.
So maybe the problem with TLS is not as big as it sounds? Or am I missing something obvious here? :-)
Denis Lisov
@tanriol
Jan 26 2018 22:42
@kellytk They have different purposes. You can derive some way of printing an error-the-programmer-can-understand automatically, but it's much more difficult for error-you-can-show-the-user.
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:42
Ok, so let's say you have a coroutine. It creates Rc<something>. It clones that Rc and stores one of it into TLS, the other is left on its stack. And it suspends.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:42
side question: is Send synonymous with thread-compatible? Or am I not understanding it right?
Steve Klabnik
@steveklabnik
Jan 26 2018 22:43
Send means" can be transferred to another thread"
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:43
Another coroutine comes and looks into the TLS, takes the Rc<something> out and stars playing with it. But the first coroutine wakes up in another thread and plays with the Rc too, at the same time. This breaks things, because there's no synchronisation ‒ on the counts to free it later, or on that something.
While other languages say this is your responsibility that it doesn't happen, Rust says it'll prevent you from doing that unless you do something silly with unsafe. Moving stacks between threads is one of these silly things.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:45
@steveklabnik doesn't this imply thread compatibility?
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:46
There's Send and Sync. Sync means it can be looked at/handled by multiple threads at once.
Send means it can move from one thread to another. If something is Send, but not Sync, you can hand it to other thread, but only one thread at a time can play with it.
Steve Klabnik
@steveklabnik
Jan 26 2018 22:47
"thread compatibility" is meaningless
basically
i don't know what the definition of that term means
Kelly Thomas Kline
@kellytk
Jan 26 2018 22:47
@tanriol That's a good point. Would you happen to have an example of a well-worded fmt::Display implementation for an error type you could refer me to? I don't know if there's a consistent style for how user-facing Rust errors are worded, but if there is I'd like to be mindful of it
Alkis Evlogimenos
@alkis
Jan 26 2018 22:48
@steveklabnik thread compatible means if this piece of data is accessed by many threads it will works as long as it is immutable
Michal 'vorner' Vaner
@vorner
Jan 26 2018 22:49
Then it is what Sync means.
Alkis Evlogimenos
@alkis
Jan 26 2018 22:49
which based on how mutable and non-mutable borrows are checked in rust, somethign that is Send is also thread compatible
Steve Klabnik
@steveklabnik
Jan 26 2018 22:55
yeah that's Sync
not Send
if something is Sync, then a reference to it is Send
Alkis Evlogimenos
@alkis
Jan 26 2018 22:55
btw @vorner your example should work as long as the coroutine runtime knows that Rc can be accessed by a single thread at a time. So say this Rc is part of 2 coroutines. The are in the queues of two different threads. As long as the threads do not run at the same time it will work. If the two threads need to access this at the same time, one of the two suspends the coro and resumes it when the other thread is done. In coro runtimes one adds these constraints through some coroutine context, whereas in Rust these can be possibly computed by the compiler
@steveklabnik aha! that part I was missing. So if something is immutable and it is Send then it is also Sync
@vorner in the paragraph above: "As long as the threads do not run at the same time " -> "As long as the threads do not run the two coroutines at the same time"
Denis Lisov
@tanriol
Jan 26 2018 23:00
@kellytk It's more a question not of Rust errors, but of your application and what wording would match it.
Kelly Thomas Kline
@kellytk
Jan 26 2018 23:00
Ok thanks