<FromGitter>
<rmarronnier> Hello fellow crystalers ! I'm giving a talk about Crystal next Wednesday and I'd like to show some performance benchmarks in my slides (especially Crystal vs Ruby as the talk takes place in a ruby meetup group). Do you have any links ?
return0e has quit [Read error: Connection reset by peer]
<FromGitter>
<jwoertink> Which you can compare DB lookups in crystal vs what they look like in ActiveRecord
<FromGitter>
<rmarronnier> Thanks @jwoertink , lazy me just wanted already made eye candy.
<FromGitter>
<rmarronnier> Wow great stuff about ORMs it hits the right spot (ActiveRecord)
<FromGitter>
<jwoertink> Yeah. I'd just say if you're going to showcase that, keep in mind that it's super out of date. Chances are, the crystal specs may be a little fast, and ActiveRecord queries are probably about the same (speculation)
<FromGitter>
<ImAHopelessDev_gitlab> @oprypin yeah, I don't know if I should use timers now. as on every hit a player does to a monster, i was using `sleep`, and a fiber was created and then it checked if it's time to remove a "charge". so probably not a good idea I think. i'm going to just set "last_charge_added" to Time.local.to_unix_ms whenever they hit a monster so it resets. then in the game loop, update the `players` `update`
<FromGitter>
... method with a `delta`, check time elapsed, and remove that charge. like so: β β ```code paste, see link``` β β However, I'm not sure if this is the correct way to do it. It seems quite excessive as it really only needs to check it every 1 second, instead of every tick rate. I'm thinking of adding a method to my player c ... [https://gitter.im/crystal-lang/crystal?at=5da20baa158cfd67351b8ed0]
<FromGitter>
<Blacksmoke16> whats the reasoning of using float32?
<FromGitter>
<Blacksmoke16> vs float64
<FromGitter>
<firejox> speed, I guess
<FromGitter>
<Blacksmoke16> would the diff even be noticable?
alex`` has quit [Ping timeout: 265 seconds]
<FromGitter>
<firejox> It could.
<FromGitter>
<firejox> Large matrix product can observe the difference.
<FromGitter>
<firejox> Or ANN
<FromGitter>
<Blacksmoke16> @ImAHopelessDev_gitlab when you define a hash like `Hash(Int64, Hash(String, Int32 | Float32))` you are requiring the the inner hash be of type `Hash(String, Int32 | Float32)`, that is a key of a string and a value that can either be `Int32` or `Float32`. However if you try to assign `{"frenzyr" => 0}` to it, which has type `Hash(String, Int32)` they are incompatible, so it errors
<FromGitter>
<Blacksmoke16> the compiler has no way of knowing that the inner hash should also be allowed to have `Float32` as a value unless 1) you tell it by doing the `of String => Int32 | Float32` syntax, or assign it a hash that has both an integer and a float value
<FromGitter>
<Blacksmoke16> the same thing happens with arrays, `Array(Int32) != Array(Int32 | String)`
<FromGitter>
<Blacksmoke16> `= [1,2] of String | Int32`
<FromGitter>
<ImAHopelessDev_gitlab> I have too use a float32
<FromGitter>
<vlazar> @rmarronnier I like these benchmarks. https://github.com/smarr/are-we-fast-yet β β > The goal of this project is to assess whether a language implementation is highly optimizing and thus is able to remove the overhead of programming abstractions and frameworks. We are interested in comparing language implementations with each other and optimize their compilers as well as the run-time representation of
<FromGitter>
<ImAHopelessDev_gitlab> See my issue on Github, so I have to use a float here ` {"frenzyr" => 0f32} `. Even if I specify `extra_game_update_hash`'s hash to support Int32 and Float32, compiler errors out
<FromGitter>
<Blacksmoke16> i know, read what i said here, they aren't the same thing
dannyAAM has quit [Quit: znc.saru.moe : ZNC 1.6.2 - http://znc.in]
dannyAAM has joined #crystal-lang
<FromGitter>
<ImAHopelessDev_gitlab> > the compiler has no way of knowing that the inner hash should also be allowed to have `Float32` as a value unless 1) you tell it by doing the `of String => Int32 | Float32` syntax, or assign it a hash that has both an integer and a float value β β We specified this by using `Hash(String, Int32 | Float32)`. I don't think we should have to re-specify our types of a hash when we already
<FromGitter>
... specified the types in the ivar... that's my issue
<FromGitter>
<Blacksmoke16> you specified the type that the hash is allowed to accept
<FromGitter>
<ImAHopelessDev_gitlab> Why do we have to do "of String => Int32 | Float32", when we already explicitly specified `Hash(String, Int32 | Float32)`
<FromGitter>
<Blacksmoke16> because `{"frenzyr" => 0f32}` isn't of the same type you specified
<FromGitter>
<Blacksmoke16> its `Hash(String, Float32)` not `Hash(String, Int32 | Float32)`
<FromGitter>
<ImAHopelessDev_gitlab> "can consist of multiple types" == allowed to accept?
<FromGitter>
<ImAHopelessDev_gitlab> That's how my brain processes it.
<FromGitter>
<ImAHopelessDev_gitlab> > right, but the value you are trying to assign doesn't match it, as is it only allows Float32 β β Yes, but look at this example: β β ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5da21aa889acff6ff5e412c3]
<FromGitter>
<ImAHopelessDev_gitlab> it works, an Int32 or a Float32.
<FromGitter>
<Blacksmoke16> righ yes, the value of `buff` can be either
<FromGitter>
<Blacksmoke16> the issue is if you make type the value to be another hash, the types have to match up again
<FromGitter>
<Blacksmoke16> > @ImAHopelessDev_gitlab when you define a hash like `Hash(Int64, Hash(String, Int32 | Float32))` you are requiring the the inner hash be of type `Hash(String, Int32 | Float32)`, that is a key of a string and a value that can either be `Int32` or `Float32`. However if you try to assign `{"frenzyr" => 0}` to it, which has type `Hash(String, Int32)` they are incompatible, so it errors
<FromGitter>
<Blacksmoke16> you made it so the inner hash should be able to accept both, but as it stands that hash can only accept Int32
<FromGitter>
<Blacksmoke16> so they are incompatible
<FromGitter>
<ImAHopelessDev_gitlab> "inner hash be of type", yeah, so why doesn't it expand out to accept the union types specified, which is Int32 and Float32?
<FromGitter>
<tenebrousedge> because the hash you're trying to add doesn't have the union type
<FromGitter>
<ImAHopelessDev_gitlab> We shouldn't have to re-specify our types AGAIN just to create the hash
<FromGitter>
<Blacksmoke16> you wouldnt have to if you tried like `{"key" => 0_f32, "other_key" => 0}`
<FromGitter>
<ImAHopelessDev_gitlab> We specified the union type already
<FromGitter>
<Blacksmoke16> because in that case it matches what you typed the hash
<FromGitter>
<Blacksmoke16> i.e. has both an int32 and float32 value
<FromGitter>
<ImAHopelessDev_gitlab> We don't need to do `p.buffs["frenzy"] = 0 of Int32 | Float32`. We can just do `p.buffs["frenzy"] = 0`. Same should be for when it's an "inner hash".
<FromGitter>
<Blacksmoke16> i dont know enough about the compiler to explain it any better
<FromGitter>
<Blacksmoke16> but im pretty sure thats just not possible
<FromGitter>
<Blacksmoke16> otherwise you hash would be implicitly converted to a type that it isnt
<FromGitter>
<Blacksmoke16> your*
<FromGitter>
<Blacksmoke16> i.e. `Hash(String, Float32)` to `Hash(String, Int32 | Float32)`
<FromGitter>
<Blacksmoke16> which are totally different types
<FromGitter>
<ImAHopelessDev_gitlab> The entire point of unions (from what my brain has comprehended so far), is values can have different types. The problem I think is, unions are not multiple types, they BECOME ONE type. β β > The type of a variable or expression can consist of multiple types. β β is misleading? [https://gitter.im/crystal-lang/crystal?at=5da21c7857c2517c6af84cf0]
<FromGitter>
<ImAHopelessDev_gitlab> From @bcardiff 's post in my forum thread. They become one type
<FromGitter>
<tenebrousedge> creating lots of hash literals like that would be unusual
<FromGitter>
<tenebrousedge> I'd probably want a `record`
<FromGitter>
<Blacksmoke16> there is a difference, you typed the value that the left hash can accept, the right side hash is not that type so you have to tell it it is
<FromGitter>
<Blacksmoke16> ^
<FromGitter>
<ImAHopelessDev_gitlab> lol @ creating hashes is unusual
<FromGitter>
<ImAHopelessDev_gitlab> using hash literals is bad now?
<FromGitter>
<tenebrousedge> I mean, it's not in PHP
<FromGitter>
<Blacksmoke16> or alias it `MyType{"" => 0}`
<FromGitter>
<tenebrousedge> ^ another good option
<FromGitter>
<ImAHopelessDev_gitlab> they should just remove hashes then
<FromGitter>
<ImAHopelessDev_gitlab> if it's so unusual
<FromGitter>
<ImAHopelessDev_gitlab> so sorry for using them!
<FromGitter>
<tenebrousedge> dial back the passive aggression
<FromGitter>
<Blacksmoke16> they have their uses, but just not the go to thing like in php/ruby
<FromGitter>
<ImAHopelessDev_gitlab> @tenebrousedge you were the one who said they were unusual in the first place
<FromGitter>
<ImAHopelessDev_gitlab> not me.
FromGitter has quit [Remote host closed the connection]
FromGitter has joined #crystal-lang
<FromGitter>
<tenebrousedge> I said it's unusual to have lots of them, particularly in contrast to PHP
<FromGitter>
<tenebrousedge> and hash literals specifically
<FromGitter>
<ImAHopelessDev_gitlab> wtf does php have anything to do with this
<FromGitter>
<tenebrousedge> PHP uses Arrays (which are more like Hashes) ubiquitously
<FromGitter>
<ImAHopelessDev_gitlab> show me how hash literals are unusual please
<FromGitter>
<Blacksmoke16> because you run into type problems like this a lot :p
return0e has joined #crystal-lang
<FromGitter>
<ImAHopelessDev_gitlab> @Blacksmoke16 i've had great success with hashes until this union thing appeared
<FromGitter>
<tenebrousedge> hash literals are probably most common to find as sets of default arguments
<FromGitter>
<Blacksmoke16> and thats fine, but now you ran into a limitation of hashes
<FromGitter>
<ImAHopelessDev_gitlab> @Blacksmoke16 i just can't believe you think it's "proper" the developer has to re-specify the types they already set the type to.
<FromGitter>
<Blacksmoke16> so now all of a sudden unions are bad?
<FromGitter>
<ImAHopelessDev_gitlab> that doesn't make any sense to me
<FromGitter>
<Blacksmoke16> i mean this is what you have to deal with if you want to use hashes
<FromGitter>
<ImAHopelessDev_gitlab> yeah but it's not proper
<FromGitter>
<ImAHopelessDev_gitlab> "inner hashes with unsions" *
<FromGitter>
<Blacksmoke16> to be frank you need to start listening to other people. your attitude makes it super frustrating to work with you.
<FromGitter>
<ImAHopelessDev_gitlab> don't respond to me then
<FromGitter>
<Blacksmoke16> π will do
<FromGitter>
<ImAHopelessDev_gitlab> you always tell me i'm wrong and never listen, your attitude isn't helping either
<FromGitter>
<tenebrousedge> you never think anyone else could be right about something
<FromGitter>
<ImAHopelessDev_gitlab> no, that's you
<FromGitter>
<ImAHopelessDev_gitlab> put me down by saying using hash literals is unusual
<FromGitter>
<ImAHopelessDev_gitlab> what a joke
<FromGitter>
<tenebrousedge> I'm often in the position of answering questions, but when I ask questions, I listen to the answers
<FromGitter>
<ImAHopelessDev_gitlab> shocker incoming: not all answers are correctly
<FromGitter>
<tenebrousedge> saying that something is unusual is not a put-down
<FromGitter>
<ImAHopelessDev_gitlab> hard for you understand, i know :/
<FromGitter>
<ImAHopelessDev_gitlab> @tenebrousedge when you know i'm using hashes for this problem, yes it is
<FromGitter>
<tenebrousedge> and what, it's impossible that you could be using the wrong data structure?
<FromGitter>
<ImAHopelessDev_gitlab> hashes are a wrong data structure?
<FromGitter>
<ImAHopelessDev_gitlab> since when?
<FromGitter>
<tenebrousedge> since you're having problems with them that a `record` wouldn't have
<FromGitter>
<ImAHopelessDev_gitlab> maybe.. just maybe
<FromGitter>
<ImAHopelessDev_gitlab> the developer wants to use Hashes
<FromGitter>
<ImAHopelessDev_gitlab> but nope "that developer who wants to utilize Hashes is wrong, hashes are unusual!!, use a record!"
<FromGitter>
<tenebrousedge> hon, you're taking everything as a personal reflection. The code doesn't care
<FromGitter>
<ImAHopelessDev_gitlab> > dial back the passive aggression
<FromGitter>
<ImAHopelessDev_gitlab> sounds like you are taking things too personal
<FromGitter>
<tenebrousedge> maybe you should go learn what that phrase means
<FromGitter>
<ImAHopelessDev_gitlab> hashes are not unusual, and are perfectly fine
<FromGitter>
<tenebrousedge> it's not a reflection on you if your code can be improved
<oprypin>
hey, how's it going π
<FromGitter>
<lbarasti> Hi folks, I'm ready to announce my first crystal shard to the world, where do you suggest I advertise it? https://crystal-ann.com/ seems to be down
<FromGitter>
<lbarasti> never mind, just a certificate issue, `http` works
<FromGitter>
<tenebrousedge> right
<FromGitter>
<lbarasti> well... authenticating via github without https is going to be hard...
<FromGitter>
<lbarasti> I'll go the Twitter way!
<oprypin>
could proooobably just edit the url after the redirect - with the obvious problem that the token is plaintext and im not sure how bad that is
<oprypin>
might as well do the chat way too while you're here π
<FromGitter>
<tenebrousedge> @lbarasti I'm not quite clear when I should prefer dataclass vs. struct. Can you suggest a good rule of thumb?
gangstacat has quit [Ping timeout: 245 seconds]
<FromGitter>
<lbarasti> I'm no expert, but I'd suggest using classes gives you more flexibility. For example, *A struct cannot inherit from a non-abstract struct*
<FromGitter>
<lbarasti> whereas a class can
<FromGitter>
<tenebrousedge> that's an interesting notion
<FromGitter>
<tenebrousedge> hmm
<FromGitter>
<lbarasti> I wonder if, in highly concurrent application you might see an advantage in passing classes through channels rather than structs, as structs would need to be allocated in the stack of each Fiber? But maybe I'm misunderstanding struct allocation, so I'll let a Fiber expert answer that
<FromGitter>
<lbarasti> My (biased) rule of thumb would be: use data classes all the time, and look into migrating to structs if memory profiling your application shows memory allocation patterns that can be improved by moving data to the stack
<FromGitter>
<Blacksmoke16> iirc in some cases classes can be faster if the structs are big and passed a lot
<FromGitter>
<Blacksmoke16> as passing a pointer is faster than copying a bunch
<FromGitter>
<lbarasti> > @lbarasti my mind is the opposite, always use structs/records, then passing to classes when needed β > Those used to mutate all around may be frustrated. β β @j8r I see your rationale. I feel like there is a big cultural component in the mutable vs immutable debate [https://gitter.im/crystal-lang/crystal?at=5da2390b4afd703a4ecb9c4e]
<FromGitter>
<ilanpillemer> whatβs the cultural component?
<FromGitter>
<lbarasti> @ilanpillemer as in, looking at the Ruby community, object mutation is an integral part of Rails. That shapes the way Rubyist think of problem. Now take the Scala community. Object mutation is supported, but not recommended, and the language makes it very easy to deal with immutable objects - see case classes
<FromGitter>
<lbarasti> my point is, I don't think we have defined a no-turning-back direction in Crystal, yet, so it's good to let the community explore different options
<FromGitter>
<tenebrousedge> I'd hesitate to say that Rails is the entirety of Ruby, but I may or may not be working on a Rails app right this second π
absolutejam4 has quit [Ping timeout: 268 seconds]
<FromGitter>
<tenebrousedge> Crystal does have a slightly larger focus on immutability
<FromGitter>
<lbarasti> > I'd hesitate to say that Rails is the entirety of Ruby, but I may or may not be working on a Rails app right this second π β β Me too! Totally not what I meant :D
<FromGitter>
<j8r> There are good reasons to use structs by default, for perf, excluding the mutability
<FromGitter>
<j8r> If I have the choice, I prefer structs because they are usually more stable. β But passing classes around by reference is very useful.
<FromGitter>
<ilanpillemer> if immutability is a big thing, tail recursion probably is important too. Does Crystal do tail recursion?
<dwdv_>
LLVM handles TCO, yes. But it doesn't seem to be required as it is in scheme.
<dwdv_>
Coming from dlang, I'm still wondering why we have both the enumerate as well as the iterator modules when they're so similar. `arr.each.map(...).slice(...).each...` feels a lot more cumbersome than simply appending a `to_a` should you need the actual data structure (or inferring it when you print, for example).
<FromGitter>
<tenebrousedge> `Iterator` is lazily evaluated
<FromGitter>
<tenebrousedge> and it's relatively rare to need `each`
<dwdv_>
Yes, I know. But wasn't it made the default wheneve you `.map`
<dwdv_>
Man, rough typing.
<dwdv_>
Yes, I know. But why wasn't it made the default whenever you use `.map` and such?
<FromGitter>
<tenebrousedge> because Ruby is not lazy by default
<FromGitter>
<tenebrousedge> and probably not Smalltalk either
<dwdv_>
"and it's relatively rare to need `each`" - How so? Don't you need it before each and every popular transformer like `map`, `select`, `flat_map` and so on?
<FromGitter>
<tenebrousedge> no
<dwdv_>
Let's see how long it takes getting used to it. Right now it feels like a chore remembering each iterator procedure that might return an array instead of an iterator.