<FromGitter>
<watzon> @Blacksmoke16 when using `find_by` in Granite, is there something special that has to be done to fetch related models? I'm doing this ⏎ ⏎ ```Models::ChatMember.find_by(chat_id: message.chat.id, user_id: from_user.id)``` ⏎ ⏎ and it's finding the record, but all of the fields on the record that don't have a default value are nil, even though in the database the fields have values.
<FromGitter>
<Blacksmoke16> Like from a relationship?
<FromGitter>
<watzon> Yeah. Just a sec, I'll show a gist with the models.
<FromGitter>
<Blacksmoke16> deff seems to be being selected
<FromGitter>
<watzon> So for the related models it's using `NULL` as the `id`
<FromGitter>
<Blacksmoke16> :thinking:
<FromGitter>
<Blacksmoke16> thinking about this stuff hurt my brain
<FromGitter>
<watzon> Hahaha same. More so I think because I don't know what's happening underneath.
<FromGitter>
<Blacksmoke16> this is what you get when you do `Models::ChatMember.find_by(chat_id: message.chat.id, user_id: from_user.id)`
<FromGitter>
<watzon> Well I think the second and third queries are from trying to access `chat_member.chat` and `chat_member.user`
<FromGitter>
<watzon> But yes
<FromGitter>
<Blacksmoke16> but they happen after the chat_message oen?
<FromGitter>
<Blacksmoke16> that seems odd
<FromGitter>
<watzon> Shoudn't they? I do the query for the `ChatMember` first, then try to access the `chat` and `user` fields which I think create the additional queries
<FromGitter>
<Blacksmoke16> yea but those queries are required to supply the values for the chat member query no?
<FromGitter>
<watzon> I think they're loaded in lazily
<FromGitter>
<Blacksmoke16> possibly
<FromGitter>
<watzon> The problem with loading the `chat` and `user` seems to be that the `chat_id` and `user_id` aren't being loaded for some reason
<FromGitter>
<Afront> Can I ask how `previous_def` is implemented? I kinda want to implement it in Ruby since it's simpler to use than AMC. Tried searching in GitHub, but all I found was call_previous_def and an instance variable
<FromGitter>
<watzon> Aww shardbox.org is not at all mobile friendly
<jhass>
but with that you could just spawn { parallel(work(ch.receive), work(ch.receive), work(ch.receive) }, little macro if you want to parameterize M
<jhass>
so yeah, not really, but just spawn M fibers receiving from a channel in a loop
<jhass>
then push your items to that channel
<jhass>
it's like 10 lines of code
<livcd>
What's the "healthiest" web framework?
<livcd>
looks like amber has a healthy contributor ratio unlike the other frameworks
<oprypin>
jhass: the difficult part is actually the finish condition - what is it?
<jhass>
closing the channel
<oprypin>
4 fibers involved
<jhass>
work(channel.receive) until channel.closed?
<oprypin>
how do i know the last fiber finished
<oprypin>
wait so that's 2 channels now
<jhass>
oh, you need a backchannel?
<oprypin>
no i don't
<jhass>
but you need to wait, makes sense
<oprypin>
i need to know when the last task finished
<jhass>
just have a channel that you receive M times from and send to at the end of each worker fiber
<jhass>
I think that's what parallel does
<oprypin>
is "closing a channel" an event or does it drop not-yet-received items
<oprypin>
why drop parallel macro, that's so horrible omg
<jhass>
eh, because nobody looked at it for years, it's more than a primitive and not the kind high level concurrency abstraction most of have a vision for. So noise reduction and maintenance cost reduction
<oprypin>
like if i have 5 items in a buffered channel and then close it, will those items be possible to receive or will receive immediately get closed error
<jhass>
I actually don't know from the top of my head
<jhass>
for this one, can't you just have a buffered channel of M size, have a fiber that spawns the processes and sends them to channel, then proc.wait while proc = channel.receive ?
<jhass>
the fiber should block if the buffered channel is full
<jhass>
and if its done spawning it sends nil to break the loop
<oprypin>
well that's what i was just saying
<oprypin>
it's weird because the channel needs to be M-1 size
<jhass>
I guess
<oprypin>
i was getting some weird results too where it seemed like i needed M-2 size for whatever reason???
<jhass>
but simple enough
<jhass>
mmh, actually makes sense, one is out of the channel waiting, one is not yet in the channel but blocked by it but spawned
<oprypin>
this is also what you mentioned as what parallel macro does
_whitelogger has joined #crystal-lang
<jhass>
I mean I guessed, I didn't look at it for too long to remember
_whitelogger has joined #crystal-lang
<FromGitter>
<j8r> @watzon i think pool was already thread-safe
<FromGitter>
<j8r> How it is designed is to have one connection per fiber
<FromGitter>
<j8r> The fiber can be on an other thread or in the same thread of others, it won't matter
<FromGitter>
<marco-fp> Hi everyone! :)
<FromGitter>
<marco-fp> I've got a quick question about how to implement something in crystal, is this the place to ask?
<FromGitter>
<marco-fp> I'll shoot: I'm trying to store channels in a hash, Hash(String, Channel(String)) but I'm getting the following error: Error: undefined method '[]=' for Hash(String, Channel(String)).class ⏎ ⏎ I've read in the docs that storing dynamic values in hash is not recommended, is there a better way to do this? ⏎ ⏎ My use case is to consume data from a websocket, and based on a value (a string), send this
<FromGitter>
... message to different fibers (one spawned per channel/string value) and process the data there, to do the channel lookup depending on the string I wanted to store them in key (unique string) -> Channel in a Hash [https://gitter.im/crystal-lang/crystal?at=5ed2404e4c9b0f060d32e32b]
<raz>
(not sure if that's exactly what you're asking for, but "trying to put mixed types into a Hash" is a common source of problems - things will likely get clearer when you get that part out of the equation)
<raz>
that said, i'm not sure why your above String => Channel shouldn't work 🤔
<raz>
(but it looks like you're trying to call []= on a class instead of an instance)
rohitpaulk has joined #crystal-lang
rohitpaulk has quit [Read error: Connection reset by peer]
rohitpaulk has joined #crystal-lang
<oprypin>
marco-fp, yea this seems fine, you just made a mistake somewhere
<oprypin>
`a = Hash(String, Channel(String)); a[x] = y` versus what it should be:
lanodan has quit [Read error: Connection reset by peer]
lanodan has joined #crystal-lang
DTZUZU_ is now known as DTZUZU
DTZUZU has quit [Ping timeout: 265 seconds]
<repo>
heya!
<repo>
what alpine packages are safe to remove after building a _dynamically_ linked crystal program? i.e. what crystal deps are runtime dependencies for built executables?
DTZUZU has joined #crystal-lang
<oprypin>
repo, cant u just `ldd your_binary`
<oprypin>
and then, if it's not obvious, trace the libs back to the owning package (which on Arch i'd do with `pacman -Qo`)
<oprypin>
(uhh the "obvious" part is meant as "you may skip the latter step because "libevent-2.1.so.7" pretty obviously comes from some "libevent" package probably)
<repo>
oprypin: yeah but i basically need to do the opposite...
<repo>
hm
<oprypin>
repo, should you really be doing the opposite though?
<repo>
maybe it's too much hassle for a few MB savings
<oprypin>
start anew and add whats needed
<repo>
oprypin: but i use the crystal alpine docker image
<repo>
i want to make a small-sized image
<oprypin>
ok so don't base it from an image that's known to have unnecessary things??
<repo>
aha
<repo>
so what are you suggesting instead? basing it from an arch image? because that's not knowh to have unnecessary things :D
<repo>
*known
<repo>
(it is)
<FromGitter>
<j8r> why you don't build a statically linked program?
<oprypin>
repo, no use base alpine docker image
<oprypin>
unnecessary things are crystal itself
<oprypin>
and other libs as you've noted
<FromGitter>
<j8r> Static linking on musl is fixed, supposed to a least
<FromGitter>
<j8r> For the empty stack traces issue
<oprypin>
why try to clean it up, as a moving target, with likely worse results, instead of getting a fresh image and putting it there
<FromGitter>
<ErikAGriffin> However the compiler complains I cannot use instance variables at the top level
<FromGitter>
<asterite> Hi! There's no way to do it. Your best bet is to use a private helper method to initialize the object and call that in each spec. Alternatively, there's the spectator shard which might let you do that (I never used it)
<FromGitter>
<ErikAGriffin> Interesting, that's like one of the main tenants of testing in Ruby unless I'm just way out of touch (Using different before_each blocks in different contexts / describe blocks to have DRY code)
<FromGitter>
<watzon> Yeah spectator has that ability
<FromGitter>
<watzon> I've used it, works well
<FromGitter>
<ErikAGriffin> Interesting that it's a shard. Would it not be nice to eventually migrate that functionality to the core lib?
<FromGitter>
<watzon> Nah it's a heavy shard, much like rspec. The standard library has very minimal testing abilities and that's all it really needs.
<FromGitter>
<ErikAGriffin> Well thanks for the tip, it seems to be exactly what I was looking for
<FromGitter>
<asterite> The problem is that it's impossible to do without introducing a lot of macros. I also personally prefer avoiding such hooks because it makes understanding specs harder
<FromGitter>
<watzon> Granted there are some things they could add to the core implementation to make it a little better, but it's not strictly speaking necessary when you have the ability to install shards like spectator.
<FromGitter>
<j8r> It is not that hard to create an helper, when copying from stdlib specs
<FromGitter>
<ErikAGriffin> Could you give me an example of such a helper? Ary mentioned it above but I did not fully understand
<FromGitter>
<ErikAGriffin> That seems a little different to what Ary was suggesting but is still interesting. I'll play around a little without the shard and see what I can manage
<FromGitter>
<j8r> not really, depends if the `it` is inside or outside the helper
<FromGitter>
<ErikAGriffin> @asterite if I were to initialize the object in a helper method, that method would have to return the object correct? Because the private helper method is still at the top level, it's not like I can define instance variables within it
<FromGitter>
<j8r> just a private method will do the trick otherwise
<FromGitter>
<j8r> Why a instance variable?
<FromGitter>
<ErikAGriffin> Doesn't have to be, I just want to be able to initialize X new objects and have them available in my test
<FromGitter>
<ErikAGriffin> Instance variables are just the pattern I'm used to using from RSpec
<FromGitter>
<j8r> so, just private helper method then?
<FromGitter>
<j8r> that return a tuple, or yield the objects
<FromGitter>
<ErikAGriffin> Yes that's what I was thinking
<FromGitter>
<ErikAGriffin> Still very new to crystal, but I could do basically a named tuple with every variable I need I think
<FromGitter>
<ErikAGriffin> Looks like Spectator does use a ton of macros (especially for exactly what we're discussing) and I'm not sure I'm a fan of that syntax
<FromGitter>
<j8r> Or a struct
<FromGitter>
<j8r> I usually do a helper that yield the object, then after do the clean up
<FromGitter>
<ErikAGriffin> Interesting. Vaguely familiar with structs and pass-by-value from Swift
<FromGitter>
<j8r> the result would be the same as namedtuple, just more crystaly - and safer
<FromGitter>
<j8r> nvm not safer, just more idiomatic
<FromGitter>
<ErikAGriffin> The Tuple API Doc doesn't discuss named tuples? I was curious how to access the properties
<FromGitter>
<ErikAGriffin> Oh I see it's a different class
<FromGitter>
<j8r> NamedTuple != Tuple
<FromGitter>
<j8r> If you use class/struct with getter, you'll have `obj.something` instead of `namedtuple[:something]`
<FromGitter>
<ErikAGriffin> I see, so when you say more idiomatic syntax you're referring to `struct.my_obj` being nicer than `tuple[:my_obj]`, do I have that right?
<FromGitter>
<j8r> yep
<FromGitter>
<ErikAGriffin> lol yes thank you
<FromGitter>
<j8r> BTW namedtuple are convenient with `#each`
<FromGitter>
<j8r> simpler than iterating over ivars
<FromGitter>
<ErikAGriffin> ivars/
<FromGitter>
<j8r> instance variables, `@ivar`
<FromGitter>
<ErikAGriffin> So I'm not sure what plugin is doing it, by my Vim has a static checker on save that is catching so many would-be compile errors so quickly and I love it
alexherbo2 has joined #crystal-lang
<FromGitter>
<ErikAGriffin> Even seems to know what methods are defined on objects I'm using, even from Classes I've defined
<FromGitter>
<ErikAGriffin> Is it possible to destructure a NamedTuple to multiple assignments in one line?
<FromGitter>
<j8r> keys and values?
<FromGitter>
<j8r> you can do one lien for keys, and an other for values
<FromGitter>
<j8r> The methods return a Tuple, which can be destructured
<FromGitter>
<ErikAGriffin> Hmm.. I guess I was thinking something similar to ES6 destructuring ⏎ `tuple = {name: 'Bob', age: 17}` ⏎ `name, age = tuple`
<FromGitter>
<ErikAGriffin> Just curious, same use case of just pulling pre-made objects out for a test unit. ⏎ However with a non-named tuple something like that works correct?
<FromGitter>
<j8r> you want to test each element of the named tuple?
<FromGitter>
<j8r> An option is to use `#each` in this case
<FromGitter>
<ErikAGriffin> No it's just for pre-test setup. Let's say each unit test depends on 3 separate objects, that need to be instantiated before each test. Using the struct method would be something like this: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ed29d3b89941d051a31f750]
<FromGitter>
<ErikAGriffin> Just more succinct and less code re-use if I'm writing this in one of many tests that use a, b, and c
<FromGitter>
<j8r> do you also need some cleanup task at the end?
<FromGitter>
<j8r> sure, you can use tuple here
<FromGitter>
<ErikAGriffin> So far I don't think so.. a, b, and c are meant to simply be new objects at the start of every test. and I don't need to do any sort of manual memory management of objects instantiated in a block I'm assuming
<FromGitter>
<j8r> ok
<FromGitter>
<j8r> If you were using files, using a method that yields is a good option too
<FromGitter>
<kinxer> Hey, more experienced software developers: how could I figure out if `a &+ b` overflows if `a` is an `Int::Primitive` and `b` is a `Number` (but, notably, they may not be the same type). If they were the same type, I could just see if the result was less than `a`, but, for example, `0_i8 &+ 1600_i32` is `64`.
<oprypin>
kinxer, uhhhh perhaps by doing `a + b`??
<FromGitter>
<kinxer> I thought I could check if `b` is greater than `a.class::MAX`, but `-100_i8 &+ 200_i32` doesn't overflow.
<FromGitter>
<kinxer> @oprypin I should have specified: I'm trying to do this without raising, because I'm using it in my saturating arithmetic library.
<FromGitter>
<kinxer> And raising is slow.
<FromGitter>
<j8r> you can use an helper with overload?
<FromGitter>
<kinxer> Can you explain what you mean?
<FromGitter>
<j8r> `add(first : Int::Primitive, second : Number)`?
<FromGitter>
<j8r> then having an other method that accepts everything else
<FromGitter>
<j8r> (with not type restrictions)
<FromGitter>
<j8r> nvm, I didn't understand correctly
<FromGitter>
<j8r> in fact, the types are irrelevant here
<FromGitter>
<kinxer> Yeah, more or less.
<FromGitter>
<j8r> we just want to know if it overflows or not, without raising
<FromGitter>
<kinxer> I specified them because I figure knowing the types tells us what methods we can use on each.
JuanMiguel has joined #crystal-lang
<oprypin>
kinxer, the way it's implemented internally in llvm is by returning {result, did_overflow}
<oprypin>
so yea would be pretty convenient if you could actually access that result
<oprypin>
unfortunately i dont think theres any way to do that
<FromGitter>
<kinxer> Oof. I now want to do a PR just to fix that method name typo.
yxhuvud has joined #crystal-lang
<oprypin>
a lot of overloads to reimpplement tho if you're acctually serious about using this
<oprypin>
wait what typo
<oprypin>
> overlow :)
<FromGitter>
<kinxer> Ah, but that's addition on the same type.
<FromGitter>
<kinxer> `primitives.cr` doesn't have any method bodies. :/
<FromGitter>
<kinxer> Ah, no. I was looking at the wrong one (not the one in `codegen/`.
<oprypin>
kinxer, yea it's really complicated to replicate
<oprypin>
so first there's type promotion and then they call an llvm func on 2 ints of the same type
lanodan has quit [Ping timeout: 272 seconds]
lanodan has joined #crystal-lang
HumanGeek has quit [Quit: Leaving]
<FromGitter>
<ErikAGriffin> Curious, why does `[].last` raise an exception instead of returning `nil`? ⏎ Not asking for an explanation of the code, I understand the source, but rather the rationale
<oprypin>
ErikAGriffin, cuz you want to get the last item of an array that has no such thing as last item. is that not enough?
<FromGitter>
<ErikAGriffin> Nil represents no such thing
<oprypin>
no
<oprypin>
anyway if u want that behavior, use `.last?`
<FromGitter>
<ErikAGriffin> Perfect, exactly what I was looking for. Where is the addition of the `?` documented? I don't see a `last?` method in the API docs
<FromGitter>
<Blacksmoke16> prob under `Enumerable`
<FromGitter>
<Blacksmoke16> just do a find in page
lanodan has quit [Read error: Connection reset by peer]
<jhass>
gotta love if you got a crash in LLVM, recompile it in debug mode just to end up at an assert that gets optimized out in relase mode and has a FIXME comment on top...
lanodan has joined #crystal-lang
_whitelogger has joined #crystal-lang
<FromGitter>
<j8r> How can I mark a forum post as solved?
<FromGitter>
<Blacksmoke16> add `[Solved]` in the title
<FromGitter>
<Blacksmoke16> idt thats a built in feature?
<FromGitter>
<j8r> meh :/
<FromGitter>
<j8r> It does not look like to be a feature
<FromGitter>
<Blacksmoke16> GH discussions has this, but its still in closed beta, plus i doubt we'd want to essentially have two forums
<yxhuvud>
(. why no, we have a bazillion different chats .)