<FromGitter>
<mjfiano:matrix.org> This is why https://git.mfiano.net/mfiano/origin.cr/src/branch/master/src/origin/aggregate.cr#L26-L30 ⏎ ⏎ Most of the operations need to perform the same assignment to each variable, and when we're talking about larger types like 16-element matrices, that would be a needless amount of code, since `@data` should always be private, unless I misunderstand.
<FromGitter>
<Blacksmoke16> i suppose, just feels a bit weird
<FromGitter>
<Blacksmoke16> but i dont really have a better suggestion
<FromGitter>
<mjfiano:matrix.org> In your example, is `delegate` even doing anything special over `property`?
<FromGitter>
<mjfiano:matrix.org> I honestly don't see what that solves over a struct with ivars and `getter`
<FromGitter>
<Blacksmoke16> not sure i follow, thats exactly what that is
<FromGitter>
<mjfiano:matrix.org> In the end you're accessing a struct's ivar in both cases, just without indirection through a heap allocated class in the latter
<FromGitter>
<Blacksmoke16> well it keeps your mutable type, but stores the data in a way thats not index based
<FromGitter>
<Blacksmoke16> struct and static arrays are both on the stack so should be pretty much the same perf wise
<FromGitter>
<mjfiano:matrix.org> But then I also need to do things like this:
<FromGitter>
<Blacksmoke16> just that strut is a bit easier to work with. I.e. methods, modules, etc
<FromGitter>
<mjfiano:matrix.org> Well you got me thinking. I don't agree with the heap container though I don't think. It might stress the GC if there are many scattered all over, even if its essentially just a pointer.
<FromGitter>
<mjfiano:matrix.org> I'm not sure though
<FromGitter>
<mjfiano:matrix.org> particularly concerned about hot paths that need many ephemeral types
<FromGitter>
<Blacksmoke16> heap container?
<FromGitter>
<mjfiano:matrix.org> Your outer type is `class`
<FromGitter>
<Blacksmoke16> so is yours no?
<FromGitter>
<mjfiano:matrix.org> No
<FromGitter>
<Blacksmoke16> oh, it used to be tho
<FromGitter>
<mjfiano:matrix.org> I have a struct with a static array @data, and always have. I thought that was what you didn't like 😆
<FromGitter>
<Blacksmoke16> at some point you had a class with a static array to store the values
<FromGitter>
<Blacksmoke16> so you could do proper chaining
<FromGitter>
<Blacksmoke16> or am i just imagining that?
<FromGitter>
<mjfiano:matrix.org> I did? Mustve been a few days ago because I don't remember with all the iterations I've been through from advice in this chat :/
<FromGitter>
<mjfiano:matrix.org> Oh I remember now. I had class with separate float ivars in my very first iteration.
<FromGitter>
<mjfiano:matrix.org> No SA
<FromGitter>
<mjfiano:matrix.org> I decided not to support chaining though, so no need for class.
<FromGitter>
<mjfiano:matrix.org> Having an allocating and mutating API for each function would be a maintenance disaster anyway, even if one essentially calls the other.
<FromGitter>
<mjfiano:matrix.org> So maybe I already have similar to what you are suggesting?
<FromGitter>
<Blacksmoke16> kinda yea, just with the idea of using a struct versus static array
<FromGitter>
<Blacksmoke16> to store the internal data
<FromGitter>
<mjfiano:matrix.org> I'm unsure what the difference would be there. Structs are just static arrays with added padding for adjacent differing types, right?
<FromGitter>
<Blacksmoke16> mainly just the ability to define methods on it, use inheritance, etc
<FromGitter>
<Blacksmoke16> versus needing to know idx 0 is x
<FromGitter>
<mjfiano:matrix.org> The idx 0 etc thing is only done in the constructors for obvious reasons. I know it could be done better I just havent thought of it yet
<FromGitter>
<Blacksmoke16> I thought about the idea of using like `struct Vector(N)` and doing like `Vector(3).new 1, 2, 3`, that doesn't work since `N` generic cant be used to build the constructor since its an instance specific thing
<FromGitter>
<Blacksmoke16> but it could be used to do like
<FromGitter>
<Blacksmoke16> and could do like `@data : StaticArray(Float64, N).new 0.0`
<FromGitter>
<mjfiano:matrix.org> But right now I'm thinking about your `#[]=` suggestion, and I think I would need to know how indexes map to the ivar names at compile time to write that
<FromGitter>
<Blacksmoke16> unless you just do like
<FromGitter>
<mjfiano:matrix.org> Idea though is all combinations of initializers are written for vectors, for example to construct a 4d vector: ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ 4D is the most I need though, and the list is pretty small, and it turns out a macro to produce them all is more code than just writing it out (in Lisp anyway, prob more for Crystal) [https://gitter.im/crys
<FromGitter>
<Blacksmoke16> some of those could maybe be solve with args that are a union of `Float64 | Vector` so it doesnt matter which you pass in which place maybe
<FromGitter>
<Blacksmoke16> but yea, thats kinda annoying
<FromGitter>
<Blacksmoke16> i cant really think of a good way to handle that without a lot of overloads or a case + loop
<FromGitter>
<mjfiano:matrix.org> `Float64 | Vector` sounds interesting, dunno if it'd work yet though
<FromGitter>
<Blacksmoke16> just moves the code into the constructor itself versus being a dedicated overload :/
<FromGitter>
<Blacksmoke16> actually is compile time safe if you dont provide enough/too many args
<FromGitter>
<Blacksmoke16> but error message isn't super great
<FromGitter>
<mjfiano:matrix.org> It's pretty slick, but not what I'm after. I don't want to parameterize the vector size...i only need 3, and it seems like that is only to make a generic sequential assignment constructor anyway
<FromGitter>
<Blacksmoke16> yea pretty much
<FromGitter>
<mjfiano:matrix.org> I'm not going to stress over it. It's all tradeoffs at the end of the day anyway, and ya know what? *Anything* I write in Crystal is automatically better and more maintainable/understandable than my Lisp version that took me like 10 years to work out all the bugs, because it's 20kloc due to generic programming being 100% slow runtime dispatch in Lisp, so open-coded everything
<FromGitter>
<mjfiano:matrix.org> The math is the bottom layer of a game engine and needs to be as fast as can be :)
<FromGitter>
<mjfiano:matrix.org> Everything sits on top :)
<FromGitter>
<mjfiano:matrix.org> Ouch
<FromGitter>
<mjfiano:matrix.org> Any way to ensure that a CONST vector (struct containing static array) cannot be mutated? Seems I can...and that is a footgun waiting to happen if I ever saw one.
szutt has joined #crystal-lang
<FromGitter>
<Blacksmoke16> There's an issue about that
<FromGitter>
<mjfiano:matrix.org> 10944 i take it?
<FromGitter>
<mjfiano:matrix.org> > Accidentally passing a StaticArray by value produces very bad LLVM IR. ⏎ ⏎ This seems like a bigger problem I think?
<FromGitter>
<mjfiano:matrix.org> But to be fair, constants in CL are also write-once globals. Everything except numbers is basically a reference type, so can set elements of "constants" just as easily.
<FromGitter>
<mjfiano:matrix.org> So not like I'm not used to it, even though this very bug in client code of my vector library creeped up a couple years ago, and it wasn't fun to track it down.
szutt has quit [Quit: Client closed]
<FromGitter>
<Blacksmoke16> #10944
<FromGitter>
<Blacksmoke16> looks like the one yea
<FromGitter>
<Blacksmoke16> I still think these should be self.new
<FromGitter>
<mjfiano:matrix.org> Yeah?
<FromGitter>
<Blacksmoke16> That pass to the one underlying initialize that accepts the 4 values
<FromGitter>
<mjfiano:matrix.org> Fair enough.
<FromGitter>
<Blacksmoke16> Would be the more proper way at least
<FromGitter>
<mjfiano:matrix.org> What about the first one there for 0-1 arity that calls `#fill`?
<FromGitter>
<Blacksmoke16> `initialize` should be used to set the internal state of the instance, `.new` should be used to transform arguments into something that fits the `initialize`
<FromGitter>
<Blacksmoke16> so in this cse `initialize` with the 1 arg is fine as that automatically gets a corresponding `.new`
<FromGitter>
<Blacksmoke16> same with the `initialize` that takes the 4 floats
<FromGitter>
<Blacksmoke16> all the others should be `.new` overloads that do `new ...`
<FromGitter>
<mjfiano:matrix.org> so0 2 initialize's and N new's for each type, gotcha
<FromGitter>
<Blacksmoke16> yea
<FromGitter>
<mjfiano:matrix.org> Cool, thanks, made the changes locally
<FromGitter>
<mjfiano:matrix.org> Is it okay the mark `.new` as always inlined? No sense in paying for new calling a new here
<FromGitter>
<Blacksmoke16> I'm not sure if that would have any benefit
<FromGitter>
<Blacksmoke16> idk if im doing this right, but from what i can tell, the generated LLVM IR is the same either wya
<FromGitter>
<mjfiano:matrix.org> Hmm, that's interesting, but the operations one does on an existing vector may internally call new to allocate a few intermediate vectors, and since the whole chain is a pretty cheap operation, I think nearly everything should be inlined, depending on generated code size.
<FromGitter>
<mjfiano:matrix.org> I'm not sure what your results would look like for such a chain of actual ops though, instead of new calling new
<FromGitter>
<pyrsmk> I'm trying to debug the compiler and I wanted to add "puts" to know the state of some variables but when I compile my program again the stack trace stay as it was before, like the new lines I added are not took into account. I thought about the compiler cache and empty it with "rm -rf `crystal env CRYSTAL_CACHE_DIR`" but I got the same output. Is there something else to take care of so the compiler can see my
<FromGitter>
... changes in its files ?
<FromGitter>
<oprypin:matrix.org> @pyrsmk: uh you need to compile the compiler
<FromGitter>
<pyrsmk> doesn't it compile itself when I run `crystal run` ?
<FromGitter>
<oprypin:matrix.org> `make clean; make` is what i usually do. in the compiler repo folder
<FromGitter>
<pyrsmk> ok, I'll do it, thanks!
<FromGitter>
<oprypin:matrix.org> @pyrsmk: no why would it add a minute-long process before every compilation
<FromGitter>
<oprypin:matrix.org> if it can be done once
<FromGitter>
<pyrsmk> indeed, I just thought that it was optimizing things by only compiling needed files ^^
postmodern has joined #crystal-lang
<postmodern>
how would you 0x80000000 as a Int32 literal?
<FromGitter>
<oprypin:matrix.org> @FromIRC: isn't that out of bounds for int32
<postmodern>
yeah, porting some C code to Crystal. WCLONE is 0x80000000 and is a flag passed via `int options`.
<FromGitter>
<HertzDevil> it's undesirable because if the inferred return type expands a module into its including types then there is a loss of information
<FromGitter>
<mjfiano:matrix.org> Makes sense
<FromGitter>
<Blacksmoke16> and in the case if you have another implementation that may cause it to return something else, it wouldn't be the same anymore
<FromGitter>
<Blacksmoke16> i.e. could result in a union
<raz>
blacksmoke16: ya, it kinda goes into the checked exceptions rabbit hole. i'm building a frameworky thing for others to use. all the types are nicely pinned down. it just makes me sad that anyone can still blow it up by leaking an exception
<FromGitter>
<Blacksmoke16> uh oh, another incoming web framework? :P
<raz>
nah, protobuf this time :D
<FromGitter>
<HertzDevil> e.g. if a stdlib method is deduced to return an `Indexable(Int16)` but there are no instantiations of that *in the stdlib*, it simply expands to `NoReturn`
<FromGitter>
<Blacksmoke16> your lib could rescue and convert them into exception types defined by your lib
<FromGitter>
<Blacksmoke16> but meh, not sure that is really needed, just let the user handle non-lib related ones
<raz>
well yea that's what it does. unknown exceptions are caught and returned as "unspecified" error. i'd just like to force the user to be specific at compile time. unfortunately doesn't seem to be possible atm.
<raz>
mhm. most languages seem to be in the "checked exceptions bad, mkay" camp nowadays. except golang.
<raz>
they're in the "we don't even give you exceptions but force you to handle everything right there anyway"-camp
<FromGitter>
<Blacksmoke16> defensive programming also kinda helps avoid them being raised as well
<raz>
i think what i'd like would be an optional `throws` annotation. so i can mark the method where i care (and do have to handle all *other* exceptions in there) but am not forced to have checked exceptions everywhere.
<raz>
kinda like how type annotations are optional in crystal
<raz>
Blacksmoke16: when building stuff for others to work on you kinda want to put them in a straightjacket tho. i think you know that feeling with athena. i know you do. :p
<FromGitter>
<Blacksmoke16> in what regard?
<raz>
well, exceptions, for example. it's so easy to forget one
<raz>
or to not even know what may bubble up from the depths of some ORM
<FromGitter>
<Blacksmoke16> ultimately thats the responsibility of the user to handle
<FromGitter>
<Blacksmoke16> the lib is doing its job by throwing a proper exception type with related extra info
<raz>
ya, but sometimes you just want to be sure everything that can possibly happen is handled
<FromGitter>
<Blacksmoke16> best you can do atm is just document it
<FromGitter>
<asterite> I think I'd like a NoRaise annotation. It gives a compile error if there's a chance for the method to raise. At least that way you can be sure you handled all errors. The problem is that almost everything can raise in Crystal and we don't have unchecked exceptions (there was a proposal for this but it wasn't liked)
<FromGitter>
<Blacksmoke16> the first issue i linked would allow for a more standardized way to document what methods raise, but still would be up to the user
<raz>
yap, `NoRaise` would be great for my use-case here. `throws` to narrow down *what* can be thrown would be even nicer, but i'd be fine with wrapping my errors into return values instead.
<FromGitter>
<Blacksmoke16> like it may not be ideal to require all exceptions to be handled where the method is called as there could be logic higher up that handles exceptions anyway
<FromGitter>
<Blacksmoke16> which is how athena handles exceptions
<straight-shoota>
I think we might continue with that exception discussion some day...
<raz>
blacksmoke16: well even that "higher up" logic (top-level exception handler) could benefit from a `NoRaise`. that way you can find all those exceptions that *should* be handled at a lower level but that you forgot about because you didn't even know they exist ;)
<FromGitter>
<Blacksmoke16> indeed
<FromGitter>
<Blacksmoke16> just meant atm you'd be best of capturing and logging unexpected ones so that you could go handle them w/o crashing the app
<raz>
well in my case crashing the app is not the worst that can happen. returning a generic error instead of a specific one is arguably worse here because then the clients bug out and it can only be detected at runtime
<FromGitter>
<Blacksmoke16> depends on the app :P
<raz>
well, throwing a 500 instead of 4xx because some junior dev forgot to handle a case is never nice :p
<FromGitter>
<Blacksmoke16> better than bringing the whole server down hehe
<FromGitter>
<Blacksmoke16> and this is why you write integration tests
<raz>
ya, but the junior dev forgets those, too. nobody ever tests their error cases. sigh.
<raz>
and when you don't even know about a possible error-case, it's hard to test for it, too ;)
<FromGitter>
<Blacksmoke16> sounds like they need to rethink their review process then
<FromGitter>
<Blacksmoke16> for sure
<FromGitter>
<Blacksmoke16> at that point best you can do is log when it happens and go fix it
<raz>
i'd prefer my compiler to prevent it before it happens (when i ask it to).
<FromGitter>
<Blacksmoke16> until that's possible*
<FromGitter>
<mjfiano:matrix.org> I have a very interesting problem with `crystal doc` that I hope someone could tell me if it is solved on 1.1.0
<FromGitter>
<mjfiano:matrix.org> Nevermind. I was under the impression that the summary included everything up until an empty commented line.
<FromGitter>
<Blacksmoke16> its up to a period or newline
<FromGitter>
<Blacksmoke16> whats the best way to print warnings like that aren't exceptions, but should be sent somewhere
<FromGitter>
<Blacksmoke16> cant imagine `puts` being the best way to do that, maybe `Log.warn`?
ming has joined #crystal-lang
<FromGitter>
<mjfiano:matrix.org> In release mode too?
<FromGitter>
<Blacksmoke16> oh thats a good idea
<FromGitter>
<Blacksmoke16> thats prob sufficient for this
ming has quit [Ping timeout: 240 seconds]
<FromGitter>
<mjfiano:matrix.org> Gosh, I'm so used to using imperative rather than third-person present tense. I document a few methods correctly, then 20 later I notice I have to go fix a bunch...constantly.
<FromGitter>
<mjfiano:matrix.org> Any non-Crystal developers brave enough to build from HEAD? How reliable has it been for everyday coding?
<FromGitter>
<mjfiano:matrix.org> Also, am I seeing this correct that it depends on an older LLVM 10, rather than 11 or 12?
<FromGitter>
<Blacksmoke16> llvm 11 works fine
<FromGitter>
<Blacksmoke16> just `make clean && make`
<FromGitter>
<Blacksmoke16> why?
<FromGitter>
<mjfiano:matrix.org> I was just noticed the Arch PKGBUILD dependencies of crystal-git
<FromGitter>
<Blacksmoke16> gotcha
<FromGitter>
<mjfiano:matrix.org> Well, failed to link with 11 after 20 minutes of compiling. I'll try 10
<FromGitter>
<Blacksmoke16> 🤔
<FromGitter>
<Blacksmoke16> are you building in release mode?
<FromGitter>
<Blacksmoke16> and thats after doing a `make clean && make`?
<FromGitter>
<mjfiano:matrix.org> Yeah
<FromGitter>
<Blacksmoke16> hm
<FromGitter>
<Blacksmoke16> dunno
<FromGitter>
<mjfiano:matrix.org> ./bin/crystal is some shell script if that helps
<FromGitter>
<Blacksmoke16> yea, that's expected
<FromGitter>
<Blacksmoke16> it should setup paths and stuff so that it uses the dev stdlib
<FromGitter>
<mjfiano:matrix.org> Well something is broken with how it builds...takes forever to print a warning, then never terminates and eats more cpui
<FromGitter>
<mjfiano:matrix.org> I dunno but I can scroll forever in htop and see thousands of bin/compiler_spec instances
<FromGitter>
<mjfiano:matrix.org> and they seem to be spawned by themself
<FromGitter>
<mjfiano:matrix.org> as a child process of itself i mean
<FromGitter>
<mjfiano:matrix.org> but not a complete linked list...starts over with compiler_spec as a root process every so often
<FromGitter>
<mjfiano:matrix.org> Well lost a lot of work. Remind me not to try building crystal myself again 😐️
<FromGitter>
<Blacksmoke16> lost work how?
<FromGitter>
<mjfiano:matrix.org> that script fork bombed me?
<FromGitter>
<Blacksmoke16> so?
<FromGitter>
<mjfiano:matrix.org> i had to restart....tried to ssh in even stalls
<FromGitter>
<Blacksmoke16> do you not save often?
<FromGitter>
<Blacksmoke16> if you're stuff is written to disk it should be fine no?
<FromGitter>
<pyrsmk> hi guys, I'm running into a weird case where I don't really know how to handle, here is it: I accept `**args` in my function and I verify if some values are defined, otherwise I set a default value; for example `obj.id = args[:id]? ? args[:id] : some_value`; in that case I got the error "missing key 'id' for named tuple NamedTuple()" on `args[:id]`... I agree with it, since the NamedTuple can be empty, we need
<FromGitter>
... to check for it, so I wrapped my code with a nice `if !args.empty?` but as I was afraid of, the compiler really didn't care even it seems there could not be any problem at runtime... do someone has any idea or a trick ?
<FromGitter>
<mjfiano:matrix.org> i do, but i had a lot of repls open with iterative math problems
<FromGitter>
<Blacksmoke16> @pyrsmk any reason you need the namedtuple in the first place versus defining the actual args you want?
<FromGitter>
<pyrsmk> @Blacksmoke16 I'm working on a factory builder
<FromGitter>
<Blacksmoke16> got an example of what you want and whats not working?
<FromGitter>
<pyrsmk> I'll try to write a reduced code to illustrate
<FromGitter>
<Blacksmoke16> 👍 perfect
<FromGitter>
<Blacksmoke16> i guess my thinking is like if you're doing `.build id: 123` then reading the `id` off the NT, why not just do `id : Int32 = some_value` and `obj.id = id`
<FromGitter>
<Blacksmoke16> versus `**args`
<FromGitter>
<pyrsmk> because I'm trying to avoid defining types for all the values since it should be inferred without any problem; just for syntactic sugar
<FromGitter>
<pyrsmk> the real gain will be when I'll add new factory strategies specifically for Granite, Moongoon, Jennifer, etc...; where there will be model auto-discovery and defaults for base types; so the factories will be really fast to write
<FromGitter>
<pyrsmk> the first usage is for specs, to ease the creation of data and the override of specific values; but it could be used in production code too I guess
<FromGitter>
<mjfiano:matrix.org> I'm still experiencing this on HEAD
<FromGitter>
<Blacksmoke16> hmm
<FromGitter>
<Blacksmoke16> so the idea is that you define a factory for your model that handles creating one up and giving values to dit?
<FromGitter>
<Blacksmoke16> creating one and assigning values on it*
ur5us has quit [Quit: Leaving]
ur5us has joined #crystal-lang
<FromGitter>
<pyrsmk> yes, without worrying about it
<FromGitter>
<pyrsmk> it can handle objects that need values at instanciation too, and there's also a way to write your custom factory strategy too, it's useful for models that are just serializable JSON for example
<FromGitter>
<Blacksmoke16> ah gotcha
<FromGitter>
<Blacksmoke16> ah, what you define are the defaults
<FromGitter>
<pyrsmk> exactly :)
<FromGitter>
<pyrsmk> and you override it for your needs
<FromGitter>
<pyrsmk> so, when you create your object you just do `Calcite.make(Item)` or `Calcite.make(Item, type: Item::ItemType::Person)`
<FromGitter>
<pyrsmk> this is very inspired by FactoryBot for Ruby
ur5us has quit [Ping timeout: 272 seconds]
<FromGitter>
<Blacksmoke16> sec
<FromGitter>
<mjfiano:matrix.org> Is assignment an expression, and if so, does it return the lhs or rhs?
<FromGitter>
<Blacksmoke16> and check if the key is in that array, versus comparing it to `nil`
<FromGitter>
<pyrsmk> good idea
<FromGitter>
<pyrsmk> this is so weird that we can use methods on an uncertain type..
<FromGitter>
<mjfiano:matrix.org> I see the problem with the shell script now. It does indeed try to call itself in one branch.
<FromGitter>
<Blacksmoke16> oh?
<FromGitter>
<mjfiano:matrix.org> `$CRYSTAL` defaults to `"crystal"` if it is not set. and If the script is called `crystal` and on your `$PATH`, the 4-way `if` at the bottom is going to spawn infinitely
<FromGitter>
<Blacksmoke16> might be worth reporting it
<FromGitter>
<mjfiano:matrix.org> This depends on how CRYSTAL_ROOT is detected. You are required to install the crystal script on your path where all the other crystal assets are relative to, not symlink it there.
<FromGitter>
<mjfiano:matrix.org> That is what I see, anyway
<FromGitter>
<mjfiano:matrix.org> Actually, this script is written in a very confusing way, that I'm not even sure I understand exactly what it's trying to solve. The call on line 153 seems to be the first error.
* FromGitter
* mjfiano:matrix.org gives up
<FromGitter>
<mjfiano:matrix.org> Funnily enough, you can't `alias mycrystal=~/path/to/crystal/bin/crystal` either, because the `crystal doc` script tries to call a literal `crystal` command.
<FromGitter>
<mjfiano:matrix.org> not even an alias of `crystal` would work. it tries to find a `command`.
<FromGitter>
<Blacksmoke16> not sure i follow
<FromGitter>
<Blacksmoke16> can just do `mycrystal doc`
<FromGitter>
<Blacksmoke16> ah, prob need another binary on path, as it uses the previous binary to compile the new binary iirc
<FromGitter>
<Blacksmoke16> idk
<FromGitter>
<mjfiano:matrix.org> Is this how the indentation should look here? I wanted to bring the first argument down on its own line so I could read it aligned easier, but the compiler yells at me. ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=60fc8d45d8381a2a838e04bd]
<FromGitter>
<Blacksmoke16> Probably could use some paren in this case
<FromGitter>
<mjfiano:matrix.org> Even if I add them the formatter indents it odd like this
<FromGitter>
<Blacksmoke16> ``````
<FromGitter>
<mjfiano:matrix.org> Hmm, for only one of my concrete classes, I don't want to derive a single class method from its abstract parent.
<FromGitter>
<mjfiano:matrix.org> But I do for all the others. Might have to create another abstract class