ChanServ changed the topic of #crystal-lang to: The Crystal programming language | https://crystal-lang.org | Fund Crystal's development: https://crystal-lang.org/sponsors | GH: https://github.com/crystal-lang/crystal | Docs: https://crystal-lang.org/docs | Gitter: https://gitter.im/crystal-lang/crystal
<FromGitter> <oprypin:matrix.org> mfiano (https://matrix.to/#/@mjfiano:matrix.org): class instances are always on the heap (scattered, so worse for cache) and, importantly, need to be garbage connected.
<FromGitter> <mjfiano:matrix.org> Yes, I'm aware of that. I'm almost thinking that is an acceptable trade-off to make in favor of a nice chained mutable method API
<FromGitter> <mjfiano:matrix.org> But I'm not certain yet. If I can find a nicer balance with structs, that'd be better.
<FromGitter> <ryanprior:matrix.org> I'd like to write data to sqlite & read it back again from query results, all without writing custom serialization code. I like how JSON::Serializable works and would like something similar. Any suggestions?
<FromGitter> <ryanprior:matrix.org> @Blacksmoke16: heck yeah, this looks fantastic
ur5us has joined #crystal-lang
<FromGitter> <ryanprior:matrix.org> Hold on though, it looks like DB:Serializable only handles creating objects from query results & not creating table schema or formatting query strings to insert data?
<FromGitter> <ryanprior:matrix.org> Or else I'm missing some big piece of this? This looks like `JSON::Serializable` except if it for some reason only gave you `from_json` but not `to_json`?
<FromGitter> <Blacksmoke16> Right
<FromGitter> <ryanprior:matrix.org> Yikes, is this seen widely as a shortcoming or not really?
<FromGitter> <Blacksmoke16> That's the hard part
<FromGitter> <Blacksmoke16> Not really, as there isn't a single way to do what you want. I.e. insert versus update
<FromGitter> <Blacksmoke16> Plus the table should already be created, that would be out of scope
<FromGitter> <Blacksmoke16> If it also handled migrations and such
<FromGitter> <ryanprior:matrix.org> Okay well it's a start I guess :)
<FromGitter> <Blacksmoke16> Inserts and updates can just use prepared statements so really np
ur5us has quit [Remote host closed the connection]
ur5us has joined #crystal-lang
ua_ has quit [Excess Flood]
ua_ has joined #crystal-lang
ua_ has quit [Ping timeout: 265 seconds]
ua_ has joined #crystal-lang
ua_ has quit [Ping timeout: 258 seconds]
ua_ has joined #crystal-lang
ur5us has quit [Ping timeout: 255 seconds]
lucf117 has quit [Remote host closed the connection]
Guest92 has joined #crystal-lang
Guest92 has quit [Client Quit]
deavmi has quit [Read error: Connection reset by peer]
deavmi has joined #crystal-lang
hightower2 has joined #crystal-lang
ur5us has joined #crystal-lang
ur5us has quit [Ping timeout: 255 seconds]
szutt has joined #crystal-lang
elf_fortrez has joined #crystal-lang
elf_fortrez has quit [Quit: Client closed]
jhass[m] has quit [Quit: Bridge terminating on SIGTERM]
fifr[m] has quit [Quit: Bridge terminating on SIGTERM]
jhass[m] has joined #crystal-lang
fifr[m] has joined #crystal-lang
<FromGitter> <mjfiano:matrix.org> Perhaps a dumb question, but is there any best practice as to when to use `x`, `@x`, or `self.x` to refer to an instance variable in an instance method? I seem to be able to use all 3 with the same effect.
sorcus has quit [Ping timeout: 276 seconds]
<FromGitter> <mjfiano:matrix.org> My guess is that `@x` is the only "safe" thing that will always resolve to an ivar, even if there is another local var or method named x...so is there no reason to use the other 2, other than to make things less explicit and confusing? :)
<FromGitter> <erdnaxeli:cervoi.se> "x" resolves to "self.x", unless you have a local var named "x"
<FromGitter> <erdnaxeli:cervoi.se> "self.x" is a method (you are probably using the macro "getter") that returns "@x"
<FromGitter> <erdnaxeli:cervoi.se> and "@x" is the actual instance var
<FromGitter> <erdnaxeli:cervoi.se> so the best practice if you want to access to the instance var is to use the instance var "@x" :)
<hightower2> if at some point later you replace access to an instance var with a getter method, then you'll need to replace @x with x or self.x
<hightower2> sometimes I wish that instead of making local vars be unprefixed, the lang designers chose to prefix local vars... so then the scope/lookup of all unprefixed vars like 'x' or 'var1' would be very uniform regardless of whether it was a property or method
<hightower2> well, I guess if one really wanted to do so, one could stick to a rule of always prefixing local vars with something, manually...
<FromGitter> <Blacksmoke16> i always use `self.` when wanting to invoke a method, and use `@x` within the type
<FromGitter> <Blacksmoke16> this way its always clear what is a method call and what isnt
<FromGitter> <Blacksmoke16> however, a good usecase for using `self.x` is if you have customer logic in the getter and/or are using a lazily initialized ivar
<hightower2> yes, that works, but what I find silly then is that we use self.x for vars and x for methods...
<FromGitter> <Blacksmoke16> can also use `x` and `x()`
<hightower2> sure, but this just continues the practice of non-uniform invocation. I would actually prefer the invocation to always be 'x', regardless of whether it is an instance var accessor or instance method
sorcus has joined #crystal-lang
<FromGitter> <Daniel-Worrall> If you have a lazy getter, I'd use `x`, but you could use `self.x` to be verbose too
<FromGitter> <Daniel-Worrall> Oh, glossed over. lazy was already mentioned
<FromGitter> <mjfiano:matrix.org> Makes sense, thanks all
<FromGitter> <mjfiano:matrix.org> Does crystal have anything like...I'm not sure what it's called, but in Nim, you can assign a slice to a slice of a variable...like: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=60f5903467b72e1bfe1da5ed]
<FromGitter> <asterite> If you remove `var ` from that code, it already works in Crystal. It's nothing special in the language, just a method call
<FromGitter> <mjfiano:matrix.org> Oh nice. It seems you can even grow shrink it with unsymmetrical ranges
<FromGitter> <mjfiano:matrix.org> Thanks @asterite
<FromGitter> <asterite> Yes :-) It's documented here: https://crystal-lang.org/api/1.1.0/Array.html#[]=(range:Range,values:Array(T))-instance-method
szutt has quit [Quit: Client closed]
<FromGitter> <mjfiano:matrix.org> Are there functions for extracting the sign and fractional components of floating-point numbers? In some languages you have something like `sign` and `fract`: ⏎ ⏎ ```sign(42.0) # 1.0 ⏎ sign (-42.0) # -1.0 ⏎ sign (0.0) # 0.0 ⏎ fract(42.123) # 0.123``` [https://gitter.im/crystal-lang/crystal?at=60f59cb2ec10653d5a4bf08b]
<FromGitter> <mjfiano:matrix.org> I suppose line 3 can be implemented differently if there is a distinction between IEEE-754 positive and negative zero
<FromGitter> <Blacksmoke16> last one could just be like `value - (value.floor)` probably?
<FromGitter> <mjfiano:matrix.org> Of course I only went down the type tower API from `Float64` to `Float`
<FromGitter> <Blacksmoke16> inherited methods are also listed towards the bottom
<FromGitter> <mjfiano:matrix.org> I suppose I was searching for the wrong half, `fract` 😆
<FromGitter> <mjfiano:matrix.org> If I have a type with *value types* (floats) for ivars, is it conventional to call a method which copies it `clone` or `dup`? In this case there is nothing to traverse for a deep copy, but I see some projects use `clone` in this case, while others use `dup`, so I'm not sure if there is a consensus.
<FromGitter> <Blacksmoke16> i imagine `dup` would be ok if the only thing you need is a new type instance
<FromGitter> <asterite> `dup` for shallow copy, `clone` for deep copy
<FromGitter> <mjfiano:matrix.org> Yes, in this case a deep copy is a shallow copy
<FromGitter> <mjfiano:matrix.org> Maybe I worded it poorly. I was stating that either would be semantically correct for this particular example, and asking if there was a general agreement of which takes preference.
<FromGitter> <asterite> I think there's no need to implement `clone` in this case given that `dup` already covers that use case
<FromGitter> <mjfiano:matrix.org> Thanks
<FromGitter> <alexherbo2> how to convert the following yaml `{ a: ["1", "2"], b: true }` to a `MyClass` with `items` being `ItemA`, `ItemB`?
<FromGitter> <alexherbo2> the real use case is to parse a `scope.yml` having the properties `roots`, `paths`, etc. in a `Scope` class, I'd like to avoid flow control to check the filters as `scope.roots`, `scope.paths`, to something like `scope.filters` having their own class
<FromGitter> <alexherbo2> I have `Scope` with `property roots` and `property paths` to pull the data from the file, but what I want when creating the instance is more something like a property `filters` doing when having `roots` keys, `Root.new(value)`, etc.
<FromGitter> <alexherbo2> so when filtering, I can just do `scope.filters.all? { |filter| filter.evaluate_with(path) }`
<FromGitter> <alexherbo2> not sure if I actually need an intermediate class to pull the data from`scope.yml`other than `Scope`
<FromGitter> <alexherbo2> like `ScopeFile` and using it to create the new `Scope` with the correct filters
<FromGitter> <Blacksmoke16> regarding your first question you can use a custom converter on that property
<FromGitter> <Blacksmoke16> that could do like `Item.new pull.read_string` and return that array
<FromGitter> <alexherbo2> currently I have a monolithic `Scope` class with hard-coded properties, it is not necessarily a problem as my scope will probably not have other props than `roots`, `paths`, `extensions`, but I realized there was too much logic in my `Scope#evaluate` method
<FromGitter> <alexherbo2> I have to re-check if the props are nil, what they are supposed to do etc.
sorcus has quit [Quit: WeeChat 3.2]
sorcus has joined #crystal-lang
<FromGitter> <mjfiano:matrix.org> Is there a builtin module with a linear interpolation function?
<FromGitter> <Blacksmoke16> if its not in `Math` id vote no
<FromGitter> <RespiteSage> I just realized I basically accidentally reimplemented the main part of Tracery (https://github.com/galaxykate/tracery) in my discord bot (https://github.com/RespiteSage/discryb).
hightower2 has quit [Ping timeout: 258 seconds]
<FromGitter> <Daniel-Worrall> Hey @RespiteSage just to let you know, discordcr was moved to shardlab/discordcr and has updates there
<FromGitter> <Daniel-Worrall> Just saw that you were using the old source in your dependencies
<FromGitter> <RespiteSage> Oh, good. I'm glad it's getting updates again.
<FromGitter> <RespiteSage> I'll fix the dependency URI.
<FromGitter> <mjfiano:matrix.org> Am I correct to assume that all optional parameters are also named? That is, there is no such thing as optional positional parameters in this language like I am used to? 😆
<FromGitter> <Blacksmoke16> no there deff is?
<FromGitter> <mjfiano:matrix.org> Can you give me an example? I've been reading the docs for a few minutes...
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/bl7s
<FromGitter> <Blacksmoke16> would just be a var with a default value
<FromGitter> <mjfiano:matrix.org> Right. But that can also be invoked with a name, so satisfies the assumption above that all optional parameters are also named?
<FromGitter> <Blacksmoke16> all arguments can also be provided via their name
<FromGitter> <mjfiano:matrix.org> Gotcha
<FromGitter> <Daniel-Worrall> Got some nice docs here thanks to :ditto: :^)
<FromGitter> <Daniel-Worrall> https://crystal-lang.org/api/1.1.0/Number.html#step(*,tolimit=nil,exclusive:Bool=false,&):Nil-instance-method
<FromGitter> <mjfiano:matrix.org> So I found another library implementing a 2D vector type, and they seem to be using a struct, and have a few methods that are clearly intended to be chained, as they return `self` (in `zero!` and `normalize!`). Is this a bug? I would expect the wrong behavior documented here to occur for subsequent chained calls: https://crystal-lang.org/reference/syntax_and_semantics/structs.html#passing-by-value
<FromGitter> ... ⏎ ⏎ Any particular reason why they didn't use a class here do you think? I'm confused why the code as it is written is okay, if it is.
<FromGitter> <Blacksmoke16> afaik you *can* mutate a struct
<FromGitter> <Blacksmoke16> which is what `.zero!` is doing ther
<FromGitter> <Blacksmoke16> but the return value from the method is a copy of `self`
<FromGitter> <mjfiano:matrix.org> Right, which makes me wonder why they have a chaining api. Clearly foo.normalize!.normalize! is going to leave the state of foo as normalized and not zeroed
<FromGitter> <mjfiano:matrix.org> err
<FromGitter> <mjfiano:matrix.org> foo.normalize!.zero!
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <mjfiano:matrix.org> Yeah this seems weird to me, supporting chaining, yet throwing away the result of n>1 (unless assigning back between each one)
<FromGitter> <mjfiano:matrix.org> Unless I completely misunderstand
ur5us has joined #crystal-lang
<FromGitter> <mjfiano:matrix.org> THis is exactly why I was hesitant to use structs as oprypin (https://matrix.to/#/@oprypin:matrix.org) recommended yesterday. I'll gladly pay for having references to heap-allocated memory if I can avoid these foot guns. Maybe I do understand and this wrong code is just making me question my sanity?
lucf117 has joined #crystal-lang
<raz> today i discovered something scandalous
<raz> you can parse an enum from a string! \o/
<FromGitter> <oprypin:matrix.org> its basically `case "Foo"; Foo;` etc
<raz> yea and it's very useful
<raz> somehow i had never crossed my mind to even try that
<raz> makes my mapping gymnastics so much easier
<raz> on an unrelated note, why does an abstract class force me to be explicit with the return values on the inheriting class
<raz> that's kinda annoying.
oprypin has quit [Read error: Connection reset by peer]
FromGitter has quit [Read error: Connection reset by peer]
oprypin_ has joined #crystal-lang
<raz> it's already written down in the parent class, why not leave to me whether i want to be verbose :<
FromGitter has joined #crystal-lang
<raz> s/return values/return types/
<FromGitter> <Blacksmoke16> otherwise you could break the abstract def if the parent said it should be String and the child returned Int32
elf_fortrez has joined #crystal-lang
elf_fortrez has quit [Client Quit]
<FromGitter> <mjfiano:matrix.org> Think I've decided on using structs, but explicitly annotate the return value as `Nil` for these small handful of side-effecting functions.
<FromGitter> <Blacksmoke16> 👍
hightower2 has joined #crystal-lang
<FromGitter> <oprypin:matrix.org> mfiano (https://matrix.to/#/@mjfiano:matrix.org): the way to make structs consistent is to make them immutable
<FromGitter> <Blacksmoke16> returning a new struct instance instead of mutaing would probably be just as performant
<FromGitter> <oprypin:matrix.org> otherwise you'll never escape the edge cases
<FromGitter> <oprypin:matrix.org> like the infamous `a.b.c = 5` where `b` is a method returning a struct, by copy obvsly
<FromGitter> <Daniel-Worrall> Anyone seen an issue about a Hash(Int, V) with a default value claiming that there's no value when using a different Int e.g. Int32 Hash accessing with Int64
<FromGitter> <Daniel-Worrall> If not, I can report it
<FromGitter> <mjfiano:matrix.org> I agree. It's just that game developers have a lot of leeway on the GPU, but are constantly trying to micro-optimize on the CPU side. So having immutable structs means allocating more, even if they are stack allocations, and sometimes you need to save state on the heap. Gamedev, and programming in general is all about tradeoffs...
<FromGitter> <Blacksmoke16> @Daniel-Worrall got an example?
<FromGitter> <Daniel-Worrall> Tested on 1.0.0, haven't tried on 1.1 yet
<FromGitter> <Daniel-Worrall> sec
<FromGitter> <Daniel-Worrall> https://carc.in/#/r/bl8s
<FromGitter> <Blacksmoke16> related to https://github.com/crystal-lang/crystal/pull/8893 i think
<FromGitter> <Blacksmoke16> i would expect that not to compile
<FromGitter> <Blacksmoke16> or because of autocasting, at least return the right result
<FromGitter> <Daniel-Worrall> Same, but I forgot I was dealing with Int64s
<FromGitter> <Daniel-Worrall> It autocasts for the error, but not for the hash checking
<FromGitter> <Daniel-Worrall> What's interesting, is that it's only for defaults https://play.crystal-lang.org/#/r/bl8z
<FromGitter> <Blacksmoke16> pretty sure it means `5_i16`, but the suffix gets stripped in the message
<FromGitter> <Daniel-Worrall> Yeah, it does
lucf117 has quit [Quit: Leaving]
<raz> Blacksmoke16: the compiler can complain when the child actually does one of these things. having to repeat all the type annotiations is kinda annoying when wanting to use abstract as an interface
<FromGitter> <Blacksmoke16> but isnt that kinda the point of the interface?
<FromGitter> <Blacksmoke16> if you dont care what the result value is, just leave it off the parent
<raz> well i *do* care. i care so much that i don't want to repeat it all over the place
<raz> if the child tries to return something else, throw errors at me
<raz> but don't force me to repeat myself in every child
<FromGitter> <Blacksmoke16> the compiler doesnt have a way to know that
<raz> it seems to know enough to complain when the child doesn't parrot the parent :<
<FromGitter> <Blacksmoke16> thats how it enforces the interface
<FromGitter> <Blacksmoke16> how it was implemented at least
<raz> yea, but can't it just assume the child has the same ret-type as the parent, rather than writing it out as an error msg
<raz> yup, that message is just silly
<FromGitter> <Blacksmoke16> got 👍 https://github.com/crystal-lang/crystal/issues/10904 then :)
<raz> Error: this method overrides Foo#foo() which has an explicit return type of String. Please add an explicit return type (String or a subtype of it) to this method as well
<raz> straight-shoota ❤️
<raz> liked & subscribed
<raz> would also hit the bell if github had one
<raz> i mean... that error message even says "please". like it knows how silly it is.
<FromGitter> <mjfiano:matrix.org> I wonder if there is a Gemini server written yet. I'd like to host a capsule, where the first thing I talk about is how much of a joy it has been learning Crystal over the last week, and how much the language is on my side and knows what I mean, contrasting it to Rust or Nim.
<FromGitter> <Blacksmoke16> time to look into web frameworks mext :P
<FromGitter> <mjfiano:matrix.org> Nah thanks. I quit the webdev industry nearly 20 years ago when I got a glimpse of what it was to become.
<FromGitter> <mjfiano:matrix.org> In instance methods that need to call `new`, is it good practice to call `self.class.new(...)` instead of `Vector2.new(...)`? I figure this is the same thing, except I don't have hard-coded type names everywhere, and can more easily refactor or turn it into generic code later.
<raz> depends on context but i'd say in most cases it's good practice, yea
<FromGitter> <mjfiano:matrix.org> Ok, also is there no Real type?
<FromGitter> <mjfiano:matrix.org> There's a lot of math that is only well-specified on real's...how can I be sure they will work on user's subtypes of Number that isn't complex?
<raz> i don't see one in the stdlib. not sure why (have never needed one myself)
<FromGitter> <mjfiano:matrix.org> Yeah, hmm, this might get hacky