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> <mattrberry> In Nim (as well as the equivalent code in c and c++) ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ Is there a way to achieve effectively what Nim does but in Crystal? [https://gitter.im/crystal-lang/crystal?at=623fae12c4350025000dfaab]
<FromGitter> <Blacksmoke16> pretty sure its more so because `Foo` is a struct
<FromGitter> <Blacksmoke16> so you're setting the value on a copy of it
<FromGitter> <Blacksmoke16> if you need to mutate it, just use a class?
<FromGitter> <mattrberry> But in Crystal, this works fine ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=623fae81e9cb3c52ae35addb]
<FromGitter> <Blacksmoke16> there are still mutable, but are some gotcha, like you ran into here and what's described in the book
<FromGitter> <mattrberry> Yeah I've seen that before in the book which is why I ended up using classes in the library I wrote last year, but after seeing the Nim behavior recently, I was wondering again *why* crystal behaves this way
<FromGitter> <Blacksmoke16> just how structs/value types work afaik :shrug:
<FromGitter> <mattrberry> For example, integers are also values, yet this works ⏎ ⏎ ```a = Array(Foo).new(2, 0) ⏎ a[1] += 1``` [https://gitter.im/crystal-lang/crystal?at=623faf34161ffc40d7d488a3]
<FromGitter> <Blacksmoke16> they're intended to be small, immutable things, or stateless wrappers around other reference types
<FromGitter> <Blacksmoke16> idt thats the same thing `a[1] += 1` is the same as `a[1] = a[1] + 1` so you're just reassigning that index, not mutating it
<FromGitter> <Blacksmoke16> which works fine because array is a reference type
<FromGitter> <mattrberry> Ahh
<FromGitter> <mattrberry> So my only way of accomplishing something like this would be to overload some operator on Foo, then use it as an assignment operator I guess..
<FromGitter> <Blacksmoke16> or just use a class
<FromGitter> <Blacksmoke16> mutable structs are kinda a smell
<FromGitter> <mattrberry> I'm currently using classes, but I have a decent feeling this will realistically improve performance by a good margin in my *very* specific case :p
<FromGitter> <Blacksmoke16> oh boy, guess we'll find out ha
<FromGitter> <Blacksmoke16> maybe go for a classic immutable design in that like `.value = 1` actually does like `self.class.new value`
<FromGitter> <Blacksmoke16> and returns a new instance of the struct?
<FromGitter> <mattrberry> ```code paste, see link``` ⏎ ⏎ Heh, this makes me feel dirty [https://gitter.im/crystal-lang/crystal?at=623fb250d1b64840db867ea6]
<FromGitter> <mattrberry> I guess this likely doesn't buy me anything though
<FromGitter> <Blacksmoke16> dont think so
<FromGitter> <Blacksmoke16> returning `self` still returns a copy
<FromGitter> <mattrberry> Yup
<FromGitter> <mattrberry> In my very specific usecase where I figured using structs might help, I effectively have an array of objects that I need to access and mutate millions of times per second. Currently, each assignment means ⏎ ⏎ 1) Fetch reference at index ⏎ 2) Follow reference to object ⏎ 3) Mutate ... [https://gitter.im/crystal-lang/crystal?at=623fb358e9cb3c52ae35b4d7]
<FromGitter> <mattrberry> And I figured that over millions of times per second, this would make a decent difference in the runtime performance of my application
<FromGitter> <Blacksmoke16> do a small benchmark?
<FromGitter> <Blacksmoke16> class versus return new instance?
ur5us has joined #crystal-lang
<FromGitter> <mattrberry> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=623fba6a99d94f5f0c6db09c]
<FromGitter> <mattrberry> Marginal
<FromGitter> <mattrberry> Across a few tests structs as defined above always win, but only by a tiny margin every time
<FromGitter> <mattrberry> Using this example fwiw ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=623fbb290466b352a439d4cd]
<FromGitter> <Blacksmoke16> So guess it's a non issue?
ur5us has quit [Ping timeout: 240 seconds]
<FromGitter> <mattrberry> Hmm maybe? I'm comparing to nim right now, where running this ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ in debug yields roughly equal times, while in release the structs proc runs *way* faster. I have to imagine it's being optimized out entirely, though.. I will check the generated code later [https://gitter.im/crystal-lang/crystal?at=623fcde0161ffc40d7d4ba6f]
<FromGitter> <mattrberry> Assuming it's optimizing out the loop completely, I'll need to look into how to make it not do that before I can accurately compare
<FromGitter> <mattrberry> I wonder if internally Nim turns the `structs[0].value = 1` into a `structs[0] = structs[0].value = 1`..
<FromGitter> <mattrberry> Although I know I can do `var struct {.byAddr.} = structs[0]` and store a variable containing the mutable struct in the array
renich has quit [Quit: Leaving]
ur5us has joined #crystal-lang
jmdaemon has quit [Ping timeout: 240 seconds]
ur5us has quit [Ping timeout: 240 seconds]
jmdaemon has joined #crystal-lang
wolfshappen has quit [Read error: Connection reset by peer]
ur5us has joined #crystal-lang
wolfshappen has joined #crystal-lang
sagax has quit [Quit: Konversation terminated!]
<FromGitter> <moe:busyloop.net> @Blacksmoke16: sorry to be the bearer of bad news, but the athena `accept`-header parser is broken :P
<FromGitter> <moe:busyloop.net> that header can contain quoted strings... so #split doesn't do the right thing
<FromGitter> <Blacksmoke16> Oh?
<FromGitter> <Blacksmoke16> Got an example by chance?
<FromGitter> <Blacksmoke16> hmm
<FromGitter> <moe:busyloop.net> yup, whoever wrote that spec will hopefully not be allowed to touch a computer again
<FromGitter> <moe:busyloop.net> the spec for that http header i mean. not the poor soul who wrote that ruby gem to parse it.
<FromGitter> <Blacksmoke16> more so curious what the `accept` header that has those would be doing
<FromGitter> <moe:busyloop.net> it's for extensions: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
<FromGitter> <moe:busyloop.net> some people use it to version their APIs (e.g. put `;version=5` in there)
<FromGitter> <Blacksmoke16> ah fair point
<FromGitter> <moe:busyloop.net> i don't think anyone in their right mind would put a semicolon or comma... but well, the spec allows it
<FromGitter> <Blacksmoke16> does it?
<FromGitter> <Blacksmoke16> https://httpwg.org/specs/rfc7230.html#field.components `token` excludes delimiters
<FromGitter> <Blacksmoke16> > Delimiters are chosen from the set of US-ASCII visual characters not allowed in a token (DQUOTE and "(),/:;<=>?@[\]{}")
<FromGitter> <Blacksmoke16> so comma in there would be invalid according to the RFC no?
<FromGitter> <moe:busyloop.net> ` accept-extension = ";" token [ "=" ( token | quoted-string ) ]`
<FromGitter> <moe:busyloop.net> note the "quoted-string" in there (see what i did there? :p)
<FromGitter> <Blacksmoke16> hmm
<FromGitter> <Blacksmoke16> okay so yea i suppose it is then
<FromGitter> <Blacksmoke16> because it would be a `quoted-pair` which allows any `VCHAR` which is any ASII character i guess
<FromGitter> <moe:busyloop.net> yup, which makes that header amazingly expensive to parse
<FromGitter> <moe:busyloop.net> as if the silly semicolon stuff wasn't bad enough already. i guess just mandating the client to put the tokens in order of preference would've been too easy.
<FromGitter> <Blacksmoke16> wait
<FromGitter> <Blacksmoke16> i just tried it and it worked fine?
<FromGitter> <moe:busyloop.net> with a ; in quotes?
<FromGitter> <moe:busyloop.net> i haven't tried, but from a glance thought that would bork your parser
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=6240f3cc6b9124232054b8ef]
<FromGitter> <moe:busyloop.net> yeh, put a ; in the quotes, and another mime type after
<FromGitter> <Blacksmoke16> `application/json;key=\"A,B,C;D\",text/html` it kinda worked, but the `D` param got cut off from the params yea
<FromGitter> <moe:busyloop.net> yea, i don't think this matters in practice anyway. just wanted to share the joy after i bumped into it while dabbling on my own framework ;)
<FromGitter> <moe:busyloop.net> i doubt browsers would send headers like that. and if someone wrote a client that does... PEBCAK
<FromGitter> <Blacksmoke16> hehe, prob wait until theres a real use case to look into it :P
<FromGitter> <Blacksmoke16> > my own framework ⏎ ⏎ Oh?
<FromGitter> <moe:busyloop.net> no competition, no worries
<FromGitter> <Blacksmoke16> using some athena components? ;)
<FromGitter> <moe:busyloop.net> my whole framework prob has less lines than one of your components :P (400'ish so far)
<FromGitter> <moe:busyloop.net> but yea, wanted to lift the accept-header logic from there after discovering what a headache it is.
<FromGitter> <Blacksmoke16> feel free :P tis what they're there for
<FromGitter> <Blacksmoke16> router might also be helpful
<FromGitter> <moe:busyloop.net> nah, i got radix 💪
<FromGitter> <Blacksmoke16> athenas is faster ;)
<FromGitter> <moe:busyloop.net> faster than radix?
<FromGitter> <Blacksmoke16> https://forum.crystal-lang.org/t/athena-0-16-0/4251/3 this one rather
<FromGitter> <Blacksmoke16> so yes
<FromGitter> <Blacksmoke16> (optimizations are in Crystal 1.4.0 tho)
<FromGitter> <moe:busyloop.net> hum, maybe i'll take a look. but it'll probably drag behind that whole DI-baggage, right?
<FromGitter> <Blacksmoke16> nope, remember each component is designed to be able to be used independently outside of the framework
<FromGitter> <jrei:matrix.org> moe (https://matrix.to/#/@moe:busyloop.net): what's your framework?
<FromGitter> <moe:busyloop.net> not released yet. tho i feel like it might be worth a shard at some point later.
<FromGitter> <moe:busyloop.net> @Blacksmoke16: hmmm yea i'll give it a look. although these numbers look a bit suspicious to me. :D
<FromGitter> <jrei:matrix.org> What will be its features?
<FromGitter> <Blacksmoke16> @moe:busyloop.net feel free to run your own benchmarks :) They're legit. PCRE2 JIT regexes are just 🚀 for this kind of usage
<FromGitter> <jrei:matrix.org> I made one in the past which was compile time safe and generates docs, but few people were interested so 🤷