<FromGitter>
<mattrberry> Currently, I have one channel of audio
<FromGitter>
<mattrberry> The "Channel" classes are simple for math. The APU class effectively tells the Channel classes how much time has passed, and the Channel classes return a sample at that time in the form of a float32
<FromGitter>
<mattrberry> Sound works. By that I mean that I am playing sounds as expected through SDL. I have separate bugs where I generate the wrong tone, but the timing and everything is fine, audio is playing fine, everything is fine
<FromGitter>
<mattrberry> If I then add `@channel2 = Channel2.new` to my APU class as so ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ then I can no longer play anything through SDL audio. I'm not using @channel2 for *anything*. It's just declared on the class. I'm still generating samples and passing them to SDL. However, SDL isn't playing *anything*. I have no idea how this could possible cause that to happen
<FromGitter>
<mattrberry> Does anybody have *any* ideas? I'm so lost here
Human_G33k has quit [Ping timeout: 240 seconds]
<FromGitter>
<mattrberry> I thought just *maybe* it was something weird with the cache, like maybe it was caching the offset to the audio buffer (which I also store as an instance variable on APU). Either way, I cleared the cache to no avail
<FromGitter>
<mattrberry> I don't even know where to begin debugging this
Human_G33k has joined #crystal-lang
<jhass>
mattrberry: Uh, if codegen bug I'd expect it to crash at some point for a long running program like that. Nonetheless you may be able to tip that of a bit by changing the order of instance variables, adding a dummy one in between etc
<jhass>
but probably it's something in your logic or maaybe semantic
Human_G33k has quit [Ping timeout: 260 seconds]
HumanG33k has joined #crystal-lang
<raz>
mattrberry: since you're using bindings, does the class perhaps do something at initialization time (the part that runs when it's merely declared)?
HumanG33k has quit [Remote host closed the connection]
HumanG33k has joined #crystal-lang
<raz>
e.g. if you have `class Parent; initialize(); end` then i think A > Parent and B > Parent will both run initialize() at startup, before an instance is even created
<raz>
(just a wild guess tho)
<raz>
(ehm, and initialize was a terrible choice for the name there... i don't mean the ctor but just any method-call right in the call body ;))
<raz>
class body*
HumanG33k has quit [Remote host closed the connection]
darkstardev13 has quit [Remote host closed the connection]
<raz>
i never use any of that stuff and have it all disabled. but i'm under no delusion that law enforcement or a grumpy apple admin can turn my mics and cams on at any time
<jhass>
or TSA
<jhass>
you're not a person or object with any rights on the US border
<raz>
i think TSA doesn't have much interest in taking selfies on your devices. they're the ones with the FileVault master key ;)
<raz>
(for which admittedly there is no evidence that one actually exists, but i kinda assume the worst these days)
<FromGitter>
<naqvis> better go back to old gold nokia phones :)
<jhass>
I'm sure they have rootkits for those as well
<FromGitter>
<naqvis> agree, privacy is always a big concern
<jhass>
I mean GSM is basically broken and can be considered plaintext, so that's the problem with old phones, if they can't root them they can just use an IMSI catcher without any issues or even just passively sniff it
deavmi has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
<raz>
that's why it's good that crystal has 7 different chat rooms
<raz>
they will never know which one to follow!
<FromGitter>
<naqvis> Crystal has 7 different chat rooms? I only know gitter
<jhass>
how come you know gitter but IRC? :D
<raz>
jk, it's only two i think (well, and a bunch that are not in use)
<jhass>
some people have some weird slack I think and then some other people have another weird slack
<raz>
and matrix
<jhass>
there's a matrix channel? Matrix can connect to IRC, why wouldn't they just connect here :/
<raz>
i don't know, maybe it was supposed to. i don't use matrix, just saw the channel when i tried it one day
<FromGitter>
<naqvis> :D
<FromGitter>
<naqvis> sometime I think how hard would it be have `composite literal` construct for `Array` and `Slice`
<FromGitter>
<naqvis> It will be beneficial in cases like ⏎ ⏎ 1) more compactly initialize arrays and slices if the array/slice has many zero values and just a few non-zero values ⏎ 2) skip ("jump over") contiguous parts when enumerating elements, and the skipped elements will be initialized with the zero values ⏎ 3) specify the first couple of elements, and still specify the length (max index + 1) you want the array/slice
<raz>
debugging why one of them isn't liked in some other place of the code... hours go by fast
<jhass>
I wondered where ruby's eql? went :D
<jhass>
so A = "a"; pool.add(A); def is?(tag); name.same?(tag); end; node.is?(A)
<raz>
it even rhymes
<raz>
you can call it the namesame PR
<jhass>
naqvis: and then you can macro the whole lot; TAGS = {"a", "p", ..}; {% for tag in TAGS %}; {{tag.upcase.id}} = {{tag}}; pool.add({{tag}}); {% end %}
<FromGitter>
<naqvis> does StringPool uses hashes to store the entries?
<jhass>
I never looked
<FromGitter>
<naqvis> because in my implementation i've used FNV hash
<jhass>
actually I'm always amazed how fast crystal parses through with crystal-gobject spits out, which iss probably well above >100kloc
<jhass>
most time really is spent in codegen, so LLVM
<FromGitter>
<watzon> Even if the speed is LLVMs fault though, it can still be improved with incremental compilation and some better caching. Right now I have a couple files that contain 15000 and 5500 lines, the biggest of which is also using the `use_json_discriminator` macro, and compilation takes somewhere between 30 and 40 seconds every time. Doesn't matter if I don't change a single line of code.
<FromGitter>
<j8r> @watzon you think `use_json_discriminator` is partly responsible of this?
<FromGitter>
<watzon> Most likely. I don't think codegen via macros is really optimized at all, and that's what `use_json_discriminator` is doing.
<FromGitter>
<giuseongit> Hi folks
<FromGitter>
<watzon> The final binary when compiled in release mode is 116MB
<FromGitter>
<Blacksmoke16> o/
<FromGitter>
<watzon> And takes a couple minutes
<FromGitter>
<asterite> I would be surprised if just use `use_json_discriminator` is what makes the code take 30 seconds to compile. Do you have some shareable code?
<FromGitter>
<watzon> Sure, just a sec. I'll make a gist with the generated code.
<FromGitter>
<giuseongit> can someone explain to me why I have this output? https://play.crystal-lang.org/#/r/97aj ⏎ I though that in the `inherited` macro `@type` would be the inheriting type (aka the subclass), but this not seem to be true
yxhuvud has quit [Read error: Connection reset by peer]
yxhuvud has joined #crystal-lang
<FromGitter>
<asterite> > how fast crystal parses through ⏎ just note that the "Parse" time that shows up in `-s` is the time it takes to parse the initial file. All other requires are not taked into account. So the stats are broken. That said, the parser is the fastest thing in the pipeline
<FromGitter>
<asterite> I see a lot of duplicated code. If you refactor those into helper functions it might speed up compilation
<FromGitter>
<asterite> Or maybe it's impossible, I don't know
<FromGitter>
<watzon> What in specific do you see duplicated?
<FromGitter>
<asterite> `res = client.send("@type" => ...)` is everywhere. But I'm not sure how I would refactor that
<FromGitter>
<asterite> Anyway, I can't test how fast or slow that compiles because it's incomplete: Error: undefined constant Proton::Client
<FromGitter>
<watzon> Yeah it really can't be helped as far as I'm aware
<FromGitter>
<asterite> and unless you are calling all of those methods, there's no way 5k lines of code will be slow to compile. The lexer has about the same lines of code and it compiles really fast
<FromGitter>
<watzon> @asterite unfortunately it won't build unless you have `tdlib` installed, but you can generate the types by running `generate_types.sh`
<FromGitter>
<j8r> omg lots of types
<FromGitter>
<asterite> I can install tdlib. What's next?
<FromGitter>
<watzon> You'd have to generate the types and then attempt to run `examples/userbot.cr`. Idk if you have a telegram account, but it won't actually run without an api_id and api_hash from https://my.telegram.org
<jhass>
it's not even thaat many types, crystal-gobject with Gtk easily generates several thousand
<FromGitter>
<asterite> library not found for -lssl
<FromGitter>
<asterite> So the initial phases seem twice as fast, maybe my machine is twice as fast, but linking takes 1.54s
<jhass>
where's your cache dirs? crystal env CRYSTAL_CACHE_DIR? spinning platter or SSD?
<jhass>
linking is IO intensive IME
<FromGitter>
<watzon> Strange. I mean my computer isn't great, but it's not bad either. I have a Intel i5-7200U (4) @ 3.100GHz and 16GB of RAM. CRYSTAL_CACHE_DIR is in my home which is on an SSD.
<FromGitter>
<asterite> Also what's the output of `echo $CC` and `cc --version`?
<FromGitter>
<j8r> The exception even not necessary
<FromGitter>
<j8r> because `self[value]` will fail before
<FromGitter>
<j8r> or something inside the `if` will
<FromGitter>
<j8r> not mentioning the exception is not tested (I don't know how to triger it)
<FromGitter>
<asterite> At least LLVM_ENABLE_THREADS seems to be enabled for mac in llvm-config.h
<FromGitter>
<watzon> @asterite without `--release` mode `make crystal 88.99s user 6.07s system 189% cpu 50.277 total`
<FromGitter>
<watzon> Major difference lol
<yxhuvud>
ok. Hmm. I saw some reference claiming it will still be single-threaded inside each module. Dunno what that means in terms of llvm-crystal compiler interaction.
<FromGitter>
<watzon> Compiling happens so much faster when I leave out the static libraries, but with `-ldtjson` for some reason it refuses to load the shared library at runtime ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ed7c7c222dd444224f7c2a9]
<FromGitter>
<j8r> libtdjson, didn't know this lib
<FromGitter>
<j8r> Tower Defense JSON?
<FromGitter>
<watzon> It's for telegram haha
<FromGitter>
<watzon> tdlib is the c++ library they made to interact with the client api
<FromGitter>
<watzon> libtdjson is the c interface which uses json for communication
<FromGitter>
<watzon> Tbh I wish they would've just written the whole thing in C, or at least made a C wrapper that wraps all of the C++ functionality 1:1
<FromGitter>
<watzon> Dealing with their json interface is a pain in the ass
<FromGitter>
<watzon> Well that's much improved at least
<FromGitter>
<watzon> Would be nice to clean up that `Semantic (main)` a bit, but this is much better than the 30+ seconds I was dealing with.
<FromGitter>
<mattrberry> > *<jhass>* @mattrberry: Uh, if codegen bug I'd expect it to crash at some point for a long running program like that. Nonetheless you may be able to tip that of a bit by changing the order of instance variables, adding a dummy one in between etc ⏎ ⏎ Tried that. I also don't think it's something in my logic. I'm adding an instance variable that I'm not using, and it's causing SDL to now play audio.
<FromGitter>
... Adding `@channel2 = Channel2.new` where `Channel2` has no `initialize` method, and the `channel2` name was not previously used, should not have any effect whatsoever on anything...
<FromGitter>
<mattrberry> > *<raz>* @mattrberry: since you're using bindings, does the class perhaps do something at initialization time (the part that runs when it's merely declared)? ⏎ ⏎ This is the extent of the APU `initialize` method. None of the other classes involved define `initialize` methods ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ed7d1c122dd444224f7df58]
<FromGitter>
<mattrberry> Simply uncommenting the `@channel2 = Channel2.new` line causes SDL to not play audio, and `Channel2` is an empty class
<raz>
an empty class? so it's from the binding? it must do _something_ during initialize to, or why would you have it at all? :)
<raz>
(my guess would be that Channel.new overwrites something shared between the two)
<FromGitter>
<naqvis> also where are you initing the SDL?
<FromGitter>
<mattrberry> > *<raz>* an empty class? so it's from the binding? it must do *something* during initialize to, or why would you have it at all? :) ⏎ ⏎ I've minimized the example to test if it was still breaking. It is
<FromGitter>
<naqvis> isn't it require to initialize SDL?
<FromGitter>
<mattrberry> > *<raz>* (my guess would be that Channel.new overwrites something shared between the two) ⏎ ⏎ I used to have Channel1 and Channel2 inheriting from an abstract class, but I've also removed that while trying to find this bug. Channel2 is literally an empty class
<raz>
hm ok, if Channel2 does not inherit from anything and doesn't execute any C binding code then... sounds like a codegen bug, hmm.
<raz>
(no idea what the problem could be tho, cause Channel2.new, on a completely empty class, should merely create a small data structure for the instance in memory, not touch anything else)
<FromGitter>
<mattrberry> Yeah that's exactly the source of my confusion
<FromGitter>
<mattrberry> I spent a bunch of time debugging this. I've minimized the test case to what I've described, and at this point I'm entirely lost
<jhass>
which platform are you on, linux?
<FromGitter>
<mattrberry> Yeah, Ubuntu 18.04
<jhass>
do you know if SDL spawns threads? I guess it does
<FromGitter>
<mattrberry> I'd imagine that it does
<raz>
have you tried renaming Channel2 just for giggles? (very wild guess, perhaps Channel2 is an actual class introduced by the binding?)
<raz>
that seems very unlikely tho ;)
<raz>
also if you want to dive very deep, could perhaps strace to see what is called in what order
<raz>
(not sure if that can shed any light tho)
<FromGitter>
<mattrberry> > *<raz>* have you tried renaming Channel2 just for giggles? (very wild guess, perhaps Channel2 is an actual class introduced by the binding?) ⏎ ⏎ Yep, I've tried renaming the Channel2 class and the channel2 instance variable on the APU
<FromGitter>
<mattrberry> > *<jhass>* I'd be curious if https://github.com/jhass/crystal-malloc_pthread_shim/ makes things better, not worse or no difference ⏎ ⏎ Do I have to build crystal from source to use this?
<raz>
hm yea, then i'm out of ideas, sorry (and these were already pretty far fetched). my knowledge of bindings approaches zero, but i agree w/ jhass on "something with threads" might be another possible breadcrumb.
<jhass>
or get a nightly build, yeah
<jhass>
raz: it's less something with threads and more bdwgc's hate on them :P
<raz>
jhass: uh oh, never argue with the GC or he might bin you next :p
<jhass>
it's still far fetched but I could imagine adding the class and instance var just changes memory layout enough for the GC to subtly wreck havoc on the memory SDL allocated
<jhass>
because it triggers a GC pass at another moment or whatever
<FromGitter>
<naqvis> can't we try with GC disabled?
<FromGitter>
<naqvis> i believe there is a flag to disable to GC at build time
<FromGitter>
<naqvis> that will rule-out the GC
<jhass>
true, that might be a quicker first check
<raz>
do you build with preview-MT btw, or normally?
<raz>
+1 on trying w/o GC
<jhass>
the options to disable are building with -Dgc_none or running with GC_NO_GC=1
<jhass>
running with GC_PRINT_STATS=1 is useful to verify it indeed shuts up
<FromGitter>
<naqvis> `GC_DONT_GC=1` isn't this one?
<jhass>
ah, yeah maybe I don't remember
<FromGitter>
<Blacksmoke16> heh, *swiper no swiping*
<FromGitter>
... the buffer I pass the pointer to with 0's. Now, with garbage collection off, this random background audio stream seems to *always* play
<FromGitter>
<mattrberry> With -Dgc_none it seems to play the play sounds again. ⏎ HOWEVER: As a side note, before I ran into this bug that we're talking about, I was having another issue with SDL that I couldn't work out. Seemingly at random, *sometimes* SDL would continuously steam random audio for the entire duration of my program. I figured this was something with memory, but I couldn't figure out why, since I always initialize
<raz>
is this a binding you wrote/generated yourself or using a shard?
<jhass>
well, that seems to at least prove the theory that the GC is to blame here
<raz>
so i'm guessing probably that one
<jhass>
not sure why you would get the permanent noise, maybe some issue in your code that was just squashed by the GC overwriting some memory within SDL
<FromGitter>
<naqvis> i would say, there might be some WeakReference somewhere, which got GCed
johnny101 has quit [Quit: Konversation terminated!]
<FromGitter>
<mattrberry> Its pointer should never change
<jhass>
maybe it plays whatever's in the buffer in a loop? do you zero it after you want to stop playing?
<jhass>
idk, how any of this works tbh
<FromGitter>
<mattrberry> Yeah, the noise plays even when the buffer is entirely 0's
<FromGitter>
<mattrberry> I believe SDL is reading the wrong memory
<raz>
fwiw it might make sense to get to the bottom of the noise issue first (with GC disabled). that seems potentially easier and might solve the original issue then as well
<FromGitter>
<mattrberry> > *<raz>* i'm a bit surprised SDL doesnt malloc/maintain its own completely separate memory. but... this is all a bit too low level for me ⏎ ⏎ SDL maintains it's own buffer. The call here https://github.com/mattrberry/CryBoy/blob/master/src/cryboy/apu.cr#L195 copies the pointed to buffer into SDL's own buffer
<raz>
mattrberry: yea, but if you fill it with zeroes *and* GC is disabled, it sounds like (no pun intended) that's not where it actually reads from
* raz
scratches head
<jhass>
yeah, and I think the GC doesn't see the memory malloc'ed in a thread spawned by SDL and thus makes some good use of that same memory
<FromGitter>
<mattrberry> Do you see anything incorrect with my bindings maybe?
<jhass>
that's what my shard above tries to workaround, make the GC see everything
<jhass>
it's a bit much and I'm too infamilar with anything SDL or even low level audio to just spot I'm afraid :(
<jhass>
I only arrived at my shard above because I had something crashing and could try a ton of solutions with landing on crashes in a debugger to inspect stuff a bit
<raz>
mattrberry: can you get meaningful sound to play when you write something non-zero to the buffer?
<FromGitter>
<mattrberry> > *<jhass>* it's a bit much and I'm too infamilar with anything SDL or even low level audio to just spot I'm afraid :( ⏎ ⏎ Yeah I'm kind of in the same boat, I'm completely lost here :/
<FromGitter>
<naqvis> quick skim through code, I couldn't find any place where you are clearing the buffer?
<jhass>
this is way harder, putting a breakpoint onto SDLs internals that get called several times per second is much harder to debug
<FromGitter>
<naqvis> might that be the reason of gibberish sounds as buffer does contain the old data
<FromGitter>
<mattrberry> > *<raz>* @mattrberry: can you get meaningful sound to play when you write something non-zero to the buffer? ⏎ ⏎ Yeah, the meaningful sound always plays, but there's sometimes background audio seemingly at random
<FromGitter>
<mattrberry> > quick skim through code, I couldn't find any place where you are clearing the buffer? ⏎ ⏎ At exit?
<raz>
background noise *while* the real sound plays?
<FromGitter>
<mattrberry> > *<raz>* background noise *while* the real sound plays? ⏎ ⏎ Yeah.....
<FromGitter>
<naqvis> you are using the same buffer to feed the audio data? right?
<raz>
uff.... how would that be possible (doesn't that mean it reads from *two* buffers and overlays them?)
<jhass>
mattrberry: I'm still interested in how my shard affects things for you, if you can be bothered :) Running without GC forever is not very practical anyways I guess
* raz
really out on a limb here
<jhass>
but yeah, it'll require crystal from source or a nightly
<raz>
is it always one stereo channel = real sound, other channel = noise? (wild guess: one channel doing a proper thing, the other an uninitialized thing)
<FromGitter>
<asterite> @mattrberry that looks like the SDL bindings are wrong. Then a struct size is wrong and what happens is that it overrides other local variables in the stack and leads to very strange behavior.
<FromGitter>
<mattrberry> Once my buffer is full here https://github.com/mattrberry/CryBoy/blob/master/src/cryboy/apu.cr#L195, I queue it up in SDL. I believe SDL then copies it to an internal buffer. I just continue that process in a loop effectively. When my buffer is full, I just wait for SDL to play everything else in its queue, then queue up the buffer again. The call to SDL's `get_queued_audio_size` doesn't seem to acknowledge
<FromGitter>
... any background audio, but its there
<FromGitter>
<mattrberry> > *<jhass>* @mattrberry: I'm still interested in how my shard affects things for you, if you can be bothered :) Running without GC forever is not very practical anyways I guess ⏎ ⏎ I could give it a shot. Is there an apt package for crystal nightly? Otherwise I'll just build from source
<FromGitter>
<naqvis> i would say you should clear-up the buffer before feeding new data
<jhass>
we should have one for debian based somewhere...
<FromGitter>
<mattrberry> > @mattrberry that looks like the SDL bindings are wrong. Then a struct size is wrong and what happens is that it overrides other local variables in the stack and leads to very strange behavior. ⏎ ⏎ I don't follow. Could you please explain?
<FromGitter>
<didactic-drunk> @mattrberry Possibly related: I've had problems with c libraries that spawn their own threads and execute crystal callbacks. Does SDL do the same?
<FromGitter>
<mattrberry> > @mattrberry Possibly related: I've had problems with c libraries that spawn their own threads and execute crystal callbacks. Does SDL do the same? ⏎ ⏎ I'm not using any of SDL's callbacks, but it spawns its own threads as far as I'm aware
<jhass>
oh, ugh, I never tried linking it to a static libgc, yeah :(
<jhass>
that cannot work, since it needs to dlopen libgc
<FromGitter>
<mattrberry> > @mattrberry that looks like the SDL bindings are wrong. Then a struct size is wrong and what happens is that it overrides other local variables in the stack and leads to very strange behavior. ⏎ ⏎ Could you please help me understand this a little bit more?
<jhass>
there's probably no sane way to bypass that with the snap, so back to building from source if you want to go down that rabbit hole
<FromGitter>
<mattrberry> > *<jhass>* there's probably no sane way to bypass that with the snap, so back to building from source if you want to go down that rabbit hole ⏎ ⏎ I wouldn't know what I'm doing :/
alexherbo20 has joined #crystal-lang
<FromGitter>
<mattrberry> Any other workaround you can think of? Otherwise this kind of puts a pin in my project :/
<jhass>
I mean to be clear, I would expect my shard to have the same effect as disabling the GC, just not with disabled GC. It probably won't fix your background noise thingy anyways
alexherbo2 has quit [Ping timeout: 272 seconds]
alexherbo20 is now known as alexherbo2
<jhass>
but no, I have no other ideas
dostoyevsky has joined #crystal-lang
<FromGitter>
<mattrberry> A gameboy emulator doesn't *really* require gc, so I could almost get by without it..
<jhass>
heh :D
<jhass>
"hard mode emulator: finish the game before you run out of memory"
<FromGitter>
<naqvis> @mattrberry `LibSDL.queue_audio 1, pointerof(@buffer), BUFFER_SIZE * sizeof(Float32)` , isn't this going to provide wrong size to SDL ?
<FromGitter>
<naqvis> `LibSDL.queue_audio 1, pointerof(@buffer), BUFFER_SIZE` maybe like this?
<FromGitter>
<naqvis> might worth a try to see if this solves gibberish sound issue
<FromGitter>
<Blacksmoke16> can use the `auto_configure` macro to alter service arguments based on type, so in this case add the `converter` tag to all instance of the `ConverterInterface`
<FromGitter>
<Blacksmoke16> versus having to do `@[ADI::Register(tags: ["converter"])]` for each one
<FromGitter>
<mattrberry> Any idea if my bug described above is a known bug? Should I submit an issue? I don't even know how to properly describe that..
alexherbo24 has joined #crystal-lang
<jhass>
sorry, I'm not sure what you're referring to
alexherbo2 has quit [Ping timeout: 260 seconds]
alexherbo24 is now known as alexherbo2
<FromGitter>
<watzon> @Blacksmoke16 have you benchmarked your JSON serializer vs the built in one?
<FromGitter>
<Blacksmoke16> not really, its prob slower tho
<FromGitter>
<Blacksmoke16> sec
<FromGitter>
<watzon> I'd imagine so. It would be awesome to get simdjson like speed in Crystal.
<jhass>
evvo: how about defining a wrapper macro around property in the module and let your users use that?
<jhass>
and leave instance vars not defined through it alone
<FromGitter>
<Blacksmoke16> whats the end goal of this?
<FromGitter>
<evvo> My problem is that I want to be able to initialize objects directly, but if some of the properties that are used are not nillable that cannot happen
<FromGitter>
<Blacksmoke16> that seems less than ideal
<FromGitter>
<evvo> That "nillifying" is a problem on it's own
<FromGitter>
<Blacksmoke16> what about all the code that relies on those not being nilable?
<FromGitter>
<Blacksmoke16> what are these objects? If you have any sample code that would be 💯
<FromGitter>
<evvo> @Blacksmoke16 , looks interesting - I've never seen this
<FromGitter>
<Blacksmoke16> do your models have some common type between them?
<FromGitter>
<j8r> I doubt it will work with this class var story
<FromGitter>
<Blacksmoke16> like abstract class/module?
<FromGitter>
<evvo> Yes, models include certain module
<FromGitter>
<Blacksmoke16> Gotcha
<FromGitter>
<evvo> I'm thinking of adding a macro that will create initializer with all needed properties
<FromGitter>
<evvo> However, I would prefer not to create an instance to get the type if possible
<FromGitter>
<Blacksmoke16> I'm always not certain how to handle this for orms
<FromGitter>
<evvo> I tried to implement it without generics, however it leads to more places that needs casting
<FromGitter>
<Blacksmoke16> I.e. make all properties nilable or not
<FromGitter>
<Blacksmoke16> You can do some fancy stuff with those free variables and macros
<FromGitter>
<evvo> If I make them nillable, that will be wrong as well, as that will "pollute" the type that was defined. If I set all of these properties to a "default" value (for example, int types = 0), that will be wrong as well
<FromGitter>
<evvo> Also setting such "default" values will create another problem - what if the value is of a specific class - this means that I will have to instantiate it and set it's values as well :D
<FromGitter>
<Blacksmoke16> part of me thinks its best to define all the columns with `property!`, so they're nilable under the hood, but not when you go to use them
<FromGitter>
<Blacksmoke16> other part of me thinks its better to not do that and require the model itself define an initializer to determine how it gets instantiated
<FromGitter>
<Blacksmoke16> the latter is prob a bit more safe at compile time, but the former is a bit more flexible
<FromGitter>
<Blacksmoke16> as you could do partial hydration of the model, like if you only selected a few fields
<FromGitter>
<Blacksmoke16> idk, is tricky
<FromGitter>
<evvo> `property!` might raise at runtime, unfortunately
<FromGitter>
<Blacksmoke16> it also defines nilable getters
<FromGitter>
<Blacksmoke16> id say majority of the time you know the value isnt going to be nil
<FromGitter>
<Blacksmoke16> like the `id` for example, thats for sure not going to be `nil`, but it would be until the model is saved
<FromGitter>
<Blacksmoke16> so it has to be nilable, and you wouldnt want to do `model.id.not_nil!` all the time when you actually go to use it
<FromGitter>
<evvo> There might be no such keys - the ORM-ish library that I'm building is very different
<FromGitter>
<Blacksmoke16> oh?
<FromGitter>
<evvo> Let's say that ... ...it will be a surprise :D
<FromGitter>
<Blacksmoke16> oh boy
<FromGitter>
<evvo> I will publish it on GitHub, hopefully soon :D
<FromGitter>
<evvo> If I add a method_missing macro, it does not complains at compile time, and, if someone forgets to add the method, it's their fault
<FromGitter>
<Blacksmoke16> hm?
<FromGitter>
<evvo> ```macro method_missing(call) ⏎ raise "That method is actually missing" ⏎ end``` ⏎ ⏎ This seems to allow the compiler to "allow" the method calls that might be determined for different types (which, at compile time, are "missing" the methods) [https://gitter.im/crystal-lang/crystal?at=5ed82cef89941d051a3fd536]
<FromGitter>
<Blacksmoke16> wouldnt that happen anyway even w/o this macro?
<FromGitter>
<evvo> No, it complains that the method is missing (and it complains for the wrong type, at the wrong place)
<FromGitter>
<Blacksmoke16> mmmm ok
<FromGitter>
<evvo> That probably makes sense, since at compile time both types are valid (for example, it might return User repository or Address repository), but at runtime, we actually return only one of them
<FromGitter>
<Blacksmoke16> cant you use overloads to return the correct repo based on the type of the model?
<FromGitter>
<Blacksmoke16> then you wont have this problem of unions
zorp_ has quit [Ping timeout: 260 seconds]
<FromGitter>
<evvo> Could you show me an example ?
<FromGitter>
<Blacksmoke16> Sec
<FromGitter>
<evvo> Thanks
<FromGitter>
<Blacksmoke16> im assuming you have some type that holds all the repos?
<FromGitter>
<evvo> Yes
<FromGitter>
<ErikAGriffin> Is there anywhere I can read up on the differences between #include and #extend? I don't see anything on either in the reference, other than modules 'extending self'
<FromGitter>
<evvo> Thanks @Blacksmoke16 - I will look into it
<FromGitter>
<ErikAGriffin> Interesting. When I used the reference's search bar in the top left, "include" returned no results and "extend" only showed the result I referenced about extending self
<FromGitter>
<Blacksmoke16> np
<FromGitter>
<Blacksmoke16> at least shows the concept, i didnt think too much of how it plays into the design
<FromGitter>
<Blacksmoke16> like how repos are created etc
<FromGitter>
<ErikAGriffin> So I'm trying to learn about the `Log` api. In my main I have the following ⏎ ⏎ ```Log = ::Log.for "main" ⏎ p Log.context``` ⏎ ⏎ As soon as I add that second line of code, the line above produces the following compiler error: ... [https://gitter.im/crystal-lang/crystal?at=5ed8322022dd444224f8e69e]
<FromGitter>
<Blacksmoke16> try doing `LOG =` not `Log = `
<FromGitter>
<ErikAGriffin> That produces `Undefined constant ::Log`
<FromGitter>
<ErikAGriffin> Also that example instantiation is pulled directly from the api docs
<FromGitter>
<Blacksmoke16> well ofc update your second line to match
<FromGitter>
<Blacksmoke16> did you `require "log"`?
<FromGitter>
<ErikAGriffin> I see that may be it. Also the fact that I'm in the Program scope, I think the example from the API docs is for a module and so `::Log` is the program scope log and the `Log` is the `Module::Log`
<FromGitter>
<ErikAGriffin> I completely missed that their examples had require "log" *facepalm*
<FromGitter>
<Blacksmoke16> well done :p
<FromGitter>
<ErikAGriffin> Not all of the standard library requires a `require` statement, is it simply habit that teaches one which ones are default or not? Or is there a list somewhere describing