<o5r>
Is there any way to get all things annotated with a certain annotation at compile time? Trying to figure out a way to plug openapi definitions on top of annotations.
<FromGitter>
<Blacksmoke16> All things meaning methods or types?
<o5r>
good question. probably methods. the more I think about it the more I think I probably have it backwards
<FromGitter>
<Blacksmoke16> Oh?
<o5r>
well. it's a statically typed language with a lot of cool type stuff. i could define a few good functions to declare typed handlers. it must already exist, even.
<FromGitter>
<Blacksmoke16> Hmm
<FromGitter>
<Blacksmoke16> got an example of what you're trying to do?
<FromGitter>
<Daniel-Worrall> Something like that? Or is there a better way
<FromGitter>
<Blacksmoke16> could you just like `loop do` then add in some stuff like `break if iterations && iterations == i`
<FromGitter>
<Daniel-Worrall> I just wonder if it'll optimise out
<FromGitter>
<Daniel-Worrall> break also feels like a very forceful keyword, so I avoid it for no real reason
<FromGitter>
<Daniel-Worrall> hmm and I can return from the break too with `var = loop ... break result`
<FromGitter>
<Daniel-Worrall> What do people prefer? `{} of K => V` or `Hash(K, V).new`?
<oprypin>
Daniel-Worrall, usually 1st but proponents of 2nd are more vocal
<oprypin>
AAAAAAAAAAAa see i'm more vocal
<FromGitter>
<Daniel-Worrall> obviously 2nd has more options, but when you just need the basic
<FromGitter>
<Daniel-Worrall> Yes, you are. *pat*
<Andriamanitra>
i prefer the 2nd one mostly because {} are bit of a pain on my keyboard layout
<FromGitter>
<Daniel-Worrall> time to learn qwert
<FromGitter>
<Daniel-Worrall> at least an English variant
<FromGitter>
<Daniel-Worrall> Does a hash ever decrease its capacity?
<FromGitter>
<tenebrousedge> the comments in `hash.cr` are pretty informative
<FromGitter>
<Daniel-Worrall> I'm going through it now
<FromGitter>
<Daniel-Worrall> I'm wondering about if I should initialise a hash with a initial capacity I know as the "max" elements it'll contain, but it'll usually hold about 1/3-1/2 of that
<FromGitter>
<Daniel-Worrall> I found the bit about deleted entries not being "removed" until needed but I won't be removing
deavmi has quit [Read error: Connection reset by peer]
<FromGitter>
<tenebrousedge> how many hashes are you creating?
deavmi has joined #crystal-lang
<FromGitter>
<Daniel-Worrall> In this case, 1, but I'm curious on the possible optimisations I could put in place in future if/when I'm creating more hashes
<FromGitter>
<Daniel-Worrall> I wanna instill some good practices in my coding, so I'm curious on the inner workings
<FromGitter>
<tenebrousedge> well, the comments are more informative than I can be, but I think that I'm not often creating lots of hashes, so while I would take some effort to avoid intermediate arrays, I haven't had to worry too much about how big my hashes are
<FromGitter>
<Daniel-Worrall> yeah, ty
<FromGitter>
<Daniel-Worrall> I feel like there should be a hash method that does `.each.to_h`
<FromGitter>
<Daniel-Worrall> like `map_hash`
<FromGitter>
<tenebrousedge> `to_h` takes a block
<FromGitter>
<Blacksmoke16> hm?
<FromGitter>
<Daniel-Worrall> Oh.
<FromGitter>
<Daniel-Worrall> I'm dumb
<FromGitter>
<tenebrousedge> mp
<FromGitter>
<tenebrousedge> no
<FromGitter>
<tenebrousedge> I learned about it a few AoC challenges ago, from asterite
<FromGitter>
<Daniel-Worrall> I only paid attention to the one that is defined on Hash, not the one included by Enumerable
<FromGitter>
<Daniel-Worrall> AoC is really giving me a lot of Iterable/Enumerable insights
<FromGitter>
<tenebrousedge> I've been tormenting Enumerable for sure
<FromGitter>
<tenebrousedge> but I'm behind on them
<FromGitter>
<Daniel-Worrall> What we need is some better documentation
<FromGitter>
<Daniel-Worrall> An intermediary between Reference and Docs
<FromGitter>
<Daniel-Worrall> (by better, I mean more expansive. The docs we have are amazing, we just need *more*)
<FromGitter>
<Daniel-Worrall> Or maybe some "See also" notes on methods that are related
<FromGitter>
<Daniel-Worrall> What I get lost in are all the different methods with the same name but different params. Maybe some way to group these together
<FromGitter>
<Blacksmoke16> oh boy, dont let girng see that
<FromGitter>
<Daniel-Worrall> I have opinions, and I will share them!
<FromGitter>
<Daniel-Worrall> Ooh, one thing. I can't provide a capacity to `to_h`
<FromGitter>
<tenebrousedge> nope
<FromGitter>
<Daniel-Worrall> I feel like I should be able to
<FromGitter>
<Daniel-Worrall> At least for the block variant
<FromGitter>
<Blacksmoke16> add a monkeypatch :p
<FromGitter>
<Daniel-Worrall> I could
<FromGitter>
<tenebrousedge> I feel like there are pretty limited situations where you need that
<FromGitter>
<Daniel-Worrall> but I'd rather create an Issue and get it in for 1.0
<FromGitter>
<Daniel-Worrall> Well if you're mutating a hash or array to hash, you'll get an optimisation for allocations if you pass the capacity (assuming you're not skipping any elements)
<FromGitter>
<tenebrousedge> will you?
<FromGitter>
<Daniel-Worrall> After I search if it already exists
<FromGitter>
<tenebrousedge> I mean why not just do `arr.reduce(Hash.new(whatever size args))`
<FromGitter>
<Daniel-Worrall> Can do for my case. Will RFC and see what the community thinks
<FromGitter>
<Daniel-Worrall> Or is this more applicable for a forum post
<FromGitter>
<tenebrousedge> I mean it sounds like a feature request
<FromGitter>
<Daniel-Worrall> Indeed, so GH Issues?
<FromGitter>
<tenebrousedge> yar
<FromGitter>
<wontruefree> @kingsleyh
chachasmooth has quit [Ping timeout: 258 seconds]
chachasmooth has joined #crystal-lang
<FromGitter>
<watzon> I'm gonna have to go back and watch all the talks I missed
<FromGitter>
<watzon> Very nice to see Crystal finally having a conference though. Maybe next year we can have a physical one.
f1refly has joined #crystal-lang
f1reflyylmao has quit [Ping timeout: 240 seconds]
<FromGitter>
<Daniel-Worrall> Yeah, I only got to see half of them
<FromGitter>
<Blacksmoke16> I'll start preparing my keynote /s
<FromGitter>
<Daniel-Worrall> I'd love a physical conference
<FromGitter>
<watzon> No /s. Next year it's you and me @Blacksmoke16.
<FromGitter>
<Daniel-Worrall> Just request that you come to the UK ;)
<FromGitter>
<Blacksmoke16> 😎
<FromGitter>
<watzon> Let's make it hard for everyone and do it in Argentina
<FromGitter>
<Daniel-Worrall> Let's do it in Ary's backyard. Literally.
<FromGitter>
<Daniel-Worrall> I'd like to see that implemented
deavmi_ has joined #crystal-lang
deavmi has quit [Read error: Connection reset by peer]
<FromGitter>
<asterite> Happy to host everyone here! I can send you a picture of my backyard and then you can decide :-)
<FromGitter>
<watzon> Deal!
<raz>
hmm. is there an easy way to iterate over pairs of items in an ArrayLiteral in a macro? i'm looking for sth like `{% for name, size in %w[name_a 5 name_b 6 name_c 7] %}`
<FromGitter>
<Daniel-Worrall> omg, `each_with_index` has an offset param. TIL
<raz>
ohh, nice, didn't know that either
<raz>
anyway, n/m my question, i now solved it another way :)
<FromGitter>
<j8r> yxhuvud is Complex used instead of x,y coordinates?
<yxhuvud>
usually when I use them, at least.
<FromGitter>
<j8r> IMHO using a struct with x,y properties is simpler to understand. Or a tuple
<FromGitter>
<j8r> Plus, you can do OOP by attaching methods
<FromGitter>
<j8r> *struct or class
<oprypin>
using Complex for x,y should be reserved strictly to code golf
<yxhuvud>
Why?
<FromGitter>
<eliasjpr> Given the big success of Raw Crystal and the possible v1 release, are there any books plan for the v1 launch? For instance a book about the crystal compiler Crystal Internals, a Book about the Standard Lib, and/or a cookbook?
<FromGitter>
<j8r> It feels wrong to use complex
<oprypin>
well it's just literally wrong
<FromGitter>
<j8r> Why x is real, and y imaginary, and not the other way around?
<yxhuvud>
j8r: either one works, though the code for rotations would change.
<yxhuvud>
oprypin: No. Why do you think that?
<FromGitter>
<HertzDevil> the convention of using x for real and y for imag probably comes from atan2
<FromGitter>
<j8r> I'm not a methematician, but after looking at the properties of Complex in Wikipedia, I don't see how they are used in the context of 2D grids...
<FromGitter>
<j8r> I just see here that Complex is used as a x,y coordinates object store
<yxhuvud>
j8r: Complex numbers *is* a 2d coordinate system, which has built in really convenient ways of rotating 90 degrees.
<yxhuvud>
(and FWIW, quaternions is simularly really convenient to work with for working with 3d numbers)
<FromGitter>
<j8r> Complex could a generic... So, the inial numbers types would be preserved
<yxhuvud>
I wouldn't mind that, but it is probably an approach limited by that the implementations for some of the methods on it is using C libraries that may or may not have all the variations you'd want.
<FromGitter>
<j8r> yxhuvud I rembered using radians and atan2 for such cases, was not hard
<FromGitter>
<HertzDevil> iso c complex has Float32, Float64, and long double
<FromGitter>
<j8r> 90deg is Pi/2, 180 is Pi
<FromGitter>
<HertzDevil> ~~not really because iso c floats aren't required to be ieee-754 single/double floats~~
<FromGitter>
<j8r> I think i could use Complex for my 2D game, but I already have something working. And it will creates lots of complex, so would be a bit slower
<FromGitter>
<j8r> I don't see anything complicated in Complex, I thought it would have more code...
<FromGitter>
<Daniel-Worrall> Complex numbers are literally a 2d plot, not just in that it stores 2 numbers, but it is studied as such and the trig functions are strongly bound to it. I only complain about using it because it uses floats where AoC uses ints
<FromGitter>
<Daniel-Worrall> A generic complex class would be nice imo
<FromGitter>
<Daniel-Worrall> Do we have a good matrix shard?
o5r has quit [Ping timeout: 264 seconds]
<FromGitter>
<j8r> Agree. I don't mind Complex, it is rather simple
<FromGitter>
<j8r> Also there are much bigger chunks in the code base that could be removed
<FromGitter>
<christopherzimmerman> @Daniel-Worrall what are you looking to use the matrices for? `Num.cr` might have what you are looking for.
<FromGitter>
<christopherzimmerman> It has support for Complex matrices, as well as provides access to most plenty of linear algebra routines for them.
<FromGitter>
<erdnaxeli:cervoi.se> but it puts to test on error, not on failure
<FromGitter>
<erdnaxeli:cervoi.se> oprypin (https://matrix.to/#/@oprypin:matrix.org): it says this method blocks
<oprypin>
oops
<oprypin>
your select method is good, then. i dont understand the problem
<FromGitter>
<erdnaxeli:cervoi.se> the problem is that I do ⏎ ⏎ ```select ⏎ when channel.receive ⏎ raise "no value was expected" ⏎ else ⏎ end``` ⏎ ⏎ When the test fails, it raises, which is seen as an error and not a failure [https://gitter.im/crystal-lang/crystal?at=5fd5159a28a57c581b0c4f60]
<FromGitter>
<Blacksmoke16> `expect_raises`?
<FromGitter>
<oprypin> no but.. it should be expect not raises
<FromGitter>
<Blacksmoke16> here's a random hash question
<FromGitter>
<erdnaxeli:cervoi.se> thanks for your help :)
<FromGitter>
<Blacksmoke16> is there any benefit between these two? I'm thinking they essentially equivalent? ⏎ ⏎ https://play.crystal-lang.org/#/r/a3ql
<FromGitter>
<Blacksmoke16> but it feels weird the key and value is the same thing
<FromGitter>
<Daniel-Worrall> > If focus is true, only this test, and others marked with focus: true, will run. ⏎ This is on the `pending` docs lol
<oprypin>
Blacksmoke16, if everything is separated by a newline, then nothing is
<FromGitter>
<Blacksmoke16> hm?
<FromGitter>
<Daniel-Worrall> how can a pending test ever run :^)
<FromGitter>
<tenebrousedge> what are you trying to do @Blacksmoke16
<FromGitter>
<Blacksmoke16> keep a hash of objects identified by their object id
<FromGitter>
<Blacksmoke16> that seems to be what `compare_by_identity` does
<FromGitter>
<Blacksmoke16> but the fact that the key and value would be the same is kinda weird?
<FromGitter>
<tenebrousedge> yes
<oprypin>
Blacksmoke16, use a `Set` then??
<FromGitter>
<Blacksmoke16> oh wait, in this case i think i could
<FromGitter>
<Blacksmoke16> also have some hashes like `Hash(UInt64, EnumType).new` that could probably be `Hash(Parent, EnumType).new.compare_by_identity)`
<FromGitter>
<Blacksmoke16> instead of manually working with object id
<oprypin>
u dont even need `compare_by_identity` if u dont redefine `==`
<FromGitter>
<Blacksmoke16> hmm
<FromGitter>
<Blacksmoke16> fair point
<FromGitter>
<Blacksmoke16> so in reality it would prob be enough to just do `Hash(Parent, EnumType)` then
<oprypin>
ye
<FromGitter>
<Blacksmoke16> cool
o5r has joined #crystal-lang
<FromGitter>
<Blacksmoke16> yea that cleaned up things quite a bit
<o5r>
Blacksmoke16: that's kind of where i wanted to take my annotation stuff yesterday; OpenAPI spec at compile time would be _excellent_ for some of my use cases
<FromGitter>
<Blacksmoke16> got an example of what kind of API you're looking for?
<o5r>
not really yet. it's going to be for mostly run-of-the-mill REST stuff.
<FromGitter>
<Blacksmoke16> im familiar with the spec, but depending on how exactly you want it to work will determine if its possible
<FromGitter>
<Blacksmoke16> like i assume you're going to need to integrate into various frameworks? or?
<hightower3>
What's a good rule of thumb for deciding when I'm gonna provide initialize() with different overloads, and when I'm gonna have a series of self.from_XYZ constructors?
<FromGitter>
<Blacksmoke16> depends on the context, like what reads better and such
<FromGitter>
<Blacksmoke16> as there's not really a difference between `def self.new` and `def self.create` other than the name you call
<hightower3>
right, ok thanks
<FromGitter>
<Blacksmoke16> the former is the more ideal case when you want to just wrap the initialize calls, but the former is useful for having a more readable api
<FromGitter>
<Blacksmoke16> like `SomeException.with_errors errors`
<hightower3>
spot on
<o5r>
Blacksmoke16: haven't gotten as far as that yet. if possible I'd like to make it as "freestanding" as possible, but I'm still really new around Crystal. This should be interesting, at any rate. Failure is also an acceptable outcome.
<FromGitter>
<Blacksmoke16> 👍 im quite familiar with annotations if you want to bounce anything off me
<FromGitter>
<j8r> Based on the routes, it can generate an OpenAPI doc
<FromGitter>
<j8r> It uses types to do so, which means no possible hand-written annotation error
<FromGitter>
<j8r> hightower3 just, avoid having an initialize calling another one, use self.new instead
<FromGitter>
<j8r> Less overhead
<hightower3>
ok, thanks!
<hightower3>
Although, won't that then allocate 2 objs, or some magic happens behind?
<FromGitter>
<Blacksmoke16> hm?
<FromGitter>
<j8r> self.new is only a regular class method, vs initialize that allocates. Calling twice will do so twice
<FromGitter>
<j8r> I don't knoe about `super` though, I suspect same story
<hightower3>
Isn't new == (allocate + initialize), that is, it's new that allocates, not initialize?
<FromGitter>
<Blacksmoke16> the compiler creates a `self.new` method based on your initialize methods
<o5r>
j8r: oh that is good
<FromGitter>
<j8r> No, `def initialize` creates a special `self.new` class method, which allocates
<FromGitter>
<j8r> I don't know if this tip is in the Crystal Reference
<hightower3>
Yes, I mean, I don't understand why is e.g. def initialize(x); self.new x[0]; end better than e.g. def initialize(x); initialize x[0]; end... I thought that the first variant would allocate 2 objects
<FromGitter>
<Blacksmoke16> you do it the other way
<FromGitter>
<Blacksmoke16> `def self.new` should call your initialize methods
<hightower3>
Yes but I'm never defining any `new` methods explicitly
<FromGitter>
<Blacksmoke16> thats what `initialize` does
<hightower3>
I mean... when the code gets to the point of calling initialize(), the object has already been allocated.
<FromGitter>
<Blacksmoke16> the range `self.new` doesnt allocate anything until it calls the `initialize` based `new` method
<FromGitter>
<j8r> It should not have been already allocated hightower3
<FromGitter>
<j8r> Doing it twice is an unecessary overhead
<hightower3>
I thought that the default (the automatically created) new() method does allocate+initialize. I agree that your example above of an overriden new() method doesn't allocate anything, but that's because it's been overriden.
<hightower3>
I'll check the docs again, since obviously you're telling me that's not true
<FromGitter>
<Blacksmoke16> its not overridden, its just an extra overload
<hightower3>
yeah yeah, I mean... when you call it, it won't allocate, that's clear
<hightower3>
when you call that particular overload, that is..
<FromGitter>
<j8r> if you do manually, it will like doing `Myclass#allocate` multiple times - no point
<hightower3>
I think that calling initialize(), in runtime, regardless how many times you do it, does not trigger any allocation. The allocation was done in new() which happened before initialize() was called.
<FromGitter>
<j8r> Do benchmarks, see yourself ;)
<FromGitter>
<j8r> no no
<FromGitter>
<j8r> initialize, as you said, is self.new + allocate inside
<FromGitter>
<j8r> it creates a self.new method, or overload, which allocates. It will do so n times when called n times
<hightower3>
I think this is not in runtime -- I think this is what happens in compile time... you define your constructor args in initialize(..args..) and the compiler helpfully creates you new() method for each ..args.. types.
<hightower3>
I am almost certain that initialize() does not allocate multiple times.. because if it did, then calling initialize() would be giving you different objects each time