<FromGitter>
<aisrael> Soβ¦ currently we canβt have generic type aliases? E.g. `alias Maybe(T) = Nothing(T) | Just(T)`?
<FromGitter>
<bew> no, but you can use a struct for that
<FromGitter>
<aisrael> π‘
<FromGitter>
<bew> huh just let me think.. I had a similar problem some time ago, will check how I handled this
<FromGitter>
<bew> @aisrael why `Nothing` has a type?
<FromGitter>
<bew> and why even use this nothing/just pattern?
<FromGitter>
<bew> you don't need that in Crystal
<FromGitter>
<aisrael> Just crazy enough to try and do monads in Crystal :)
<FromGitter>
<bew> I did a little functionnal parsing with combinators in Crystal, I'll put it in a gist, maybe you'll find how to handle your crazy experiement :)
<FromGitter>
<bew> check out the link at the top, it's a tutorial in F# about it, which I used to make this experiment
<FromGitter>
<aisrael> Am starting to understand. OTOH, I guess what am treally trying to do is a bit of functional error handling: β β ```type Result<'a> = β | Success of 'a β | Failure of string ``` [https://gitter.im/crystal-lang/crystal?at=5a84e533d74ee9f50dc7230c]
<FromGitter>
<bew> yeah I decided that I didn't need the `Result`, but you'll see that I always return either `Success` with some fields, or `Failure` with a message
<FromGitter>
<bew> (line 72, just click on the link)
jnyw has joined #crystal-lang
<FromGitter>
<aisrael> True. But then if this gets used far and wide a) it becomes tedious to have to write `Success(A) | Failure` everywhere, and then b) what if you (for whatever reason) need to add another option (e.g. `SuccessWithWarnings(A)` then client code everywhere has to change, to.
<FromGitter>
<bew> a) don't write it, the Crystal compiler can figure this out for you!
<FromGitter>
<bew> b) how would you handle this in a functional lang?
<FromGitter>
<aisrael> a) Yeah, that's also true but now you kinda lose some type safety don't you? Or maybe not depending on use. But I like type annotations (almost) everywhere β b) Well, in e.g. Haskell `data Maybe a = Just a | Nothing`
<FromGitter>
<bew> a) No, it's still type safe (Crystal <3)
<FromGitter>
<bew> b) I meant, if you have to add another option like you suggested, wouldn't this change every client code everywhere too?
<FromGitter>
<aisrael> Not necessarily, right? I mean, those methods declared`foo(result : Result(Bar))` can compile unchanged. Only if you need to handle `SuccessWithWarnings(Bar)` do you need to modify the method definition, right? β β OTOH, if you declared `foo(result : Success(Bar) | Failure)` now the code won't compile if called with the result of `method : Success(Bar) | SuccessWithWarnings(Bar) | Failure`
<FromGitter>
<bew> @aisrael I agree type annotations are good to know what you have, but now that I use Crystal (too much?) I put type annotations in key places, but not every where, so for example, here, the only place where I put it was in the creation of a `Parser`, the passed function has to return a `Failure | Success(T)`, that's all needed! I could add a type annotation on `Parser#parse` method's return, but here the compiler
<FromGitter>
... will gently tell you that `@parser.call str` will return `Failure | Success(T)` and that you need to handle X case
<Papierkorb>
aisrael, It's type safe in the language sense. You could say that we prefer to "don't state the obvious". A method like `returnTheString` is obvious in what it returns. That sample may look superificial at first, but really, most methods can be written to be practically obvious what'll happen. Use type restrictions where it's not obvious (and can't be made obvious), or where you want to re-enforce a users expectation.
<FromGitter>
<aisrael> Anyway, yeah just saw #2803
<Papierkorb>
Over-restrictions actually worsens your code quality, as it makes your algorithms less generic.
duane has joined #crystal-lang
<Papierkorb>
aisrael, e.g. you have a method that operates read-only on a sequential container. Reasonable restriction: `def foo(list : Enumerable(String))` vs over restriction: `def foo(list : Array(String))`. In this sample, say you don't care about the T = String at all, it would be better to just do: `def foo(list : Enumerable)` if you want to restrict at all, or just `foo(list)`. `foo(list : Array)` would be worse.
<FromGitter>
<bew> good point about genericity, ty Papierkorb!
<FromGitter>
<aisrael> Hmmn... I guess am just looking for a way to have "ad-hoc polymorphism in a structured (type safe) way" (lifted from Haskell's type classes). β β However, TIL you can use a module/mixin as a type restriction! E.g. `Enumerable(T)`
<FromGitter>
<aisrael> And of course abstract base classes... still, I'm putting my vote in for generic type aliases :)
<Papierkorb>
You totally can, it's superb. You can also do stuff like `def combine_all(*many : Enumerable(T)) forall T`. This method will compile only if all passed arguments are Enumerables of Ts, but the kind of Enumerable doesn't matter, so you could pass an Array and a Tuple of Strings just fine
<FromGitter>
<aisrael> TIL: `forall` "keyword"
<Papierkorb>
forall is a keyword (no "" needed). You can define more than one 'type' there using comma: `forall T, U`. The type names have to be a single-letter
<Papierkorb>
iirc the fancy name was "free variables"
<FromGitter>
<bew> I personally don't think that making a crystal version of those library is useful, but you can help make a good bindings of a library like the one I mentioned in this issue, that would be great! And as the lib is already multi-plateform you would have windows support (and lot others) for free :)
<watzon>
Yeah I'm just not a big fan of C bindings personally. Even if they're more efficient, I'm willing to sacrifice a little efficiency for readability
<watzon>
Plus it's fun to learn about the inner workings of linux
<FromGitter>
<bew> sure, but a binding can be very readable you know :) (me too I tend to rewrite too much things x) )
<crystal-gh>
[crystal] bmmcginty opened pull request #5720: Ensure that HTTP::WebSocket uses SNI, just like HTTP::Client. (master...sni) https://git.io/vAZgS
<FromGitter>
<j8r> but with `{Ame: "name"}` works?!
<FromGitter>
<bew> yeah, it's because here you're using the 'traditional-with-a-method-call' creation method, and Ame is not recognized as an argument
<FromGitter>
<bew> because arguments starting with an upcased letter are not allowed
<FromGitter>
<bew> but with the literal syntax `{ab: 1}` the problem does not exist
maattdd has quit [Ping timeout: 256 seconds]
maattdd has joined #crystal-lang
bijan_awaaaay is now known as bijan_
TakeYourFreedom has joined #crystal-lang
<FromGitter>
<j8r> is it better to use `"msg" + string` or `"msg #{string}"` for performance?
<FromGitter>
<j8r> I use the latest avoid `to_s` when the variable isn't a string
<FromGitter>
<bew> I'd say the first one, but it's negligible at this level
<FromGitter>
<bew> you should use whatever you like
<FromGitter>
<straight-shoota> interpolation should usually be preferred
<FromGitter>
<bew> for just 2 string it doesn't matter, but for more than 2 string it might be more efficient yes
<FromGitter>
<j8r> ok good to know
<FromGitter>
<j8r> so why having the concatenation possibility?
<FromGitter>
<j8r> compatibility with other languages I suppose
<FromGitter>
<bew> no
<FromGitter>
<bew> it's just 2 different things, 2 ways of resolving the same problem, and both ways have their usecase
bijan_ has quit [Quit: Shutting Down Interwebs...Done.]
hightower3 has joined #crystal-lang
jnyw has quit [Quit: WeeChat 2.0.1]
hightower2 has quit [Ping timeout: 264 seconds]
tobyfree has quit [Ping timeout: 260 seconds]
Take_Your_Freedo has joined #crystal-lang
TakeYourFreedom has quit [Ping timeout: 268 seconds]
sz0 has joined #crystal-lang
<FromGitter>
<xfbs> Is there a method in crystal such that `['a', 'b', 'a', 'c', 'a', 'b'].some_meth # => {'a' => 3, 'b' => 2, 'c' => 1}` (meaning that it returns a hash or whatever with each element in the array and it's count)?
<FromGitter>
<laginha87> @xfbs you can achieve it by doing ``` group_by{ |e| e }.map{|k,v| [k, v.size]}.to_h```
<FromGitter>
<j8r> sructs are more efficient than classes, but from what I've heard it can have issues when large data are handled
Take_Your_Freedo has quit [Remote host closed the connection]
robacarp has quit [Ping timeout: 240 seconds]
maattdd has joined #crystal-lang
maattdd_ has quit [Read error: Connection reset by peer]
<txdv>
yeah, because you push struts on the stack
<txdv>
and big structs on the stack are stupid
<FromGitter>
<xfbs> Well, I think I'm just gonna use a class since performance doesn't matter so much right now
<FromGitter>
<xfbs> Btw I really love how `shards` puts all dependencies into `lib/`, it's so nice to be able to have the source code right there!
maattdd has quit [Ping timeout: 256 seconds]
maattdd has joined #crystal-lang
rohitpaulk has quit [Ping timeout: 240 seconds]
vivus has joined #crystal-lang
snsei has joined #crystal-lang
<FromGitter>
<sdogruyol> @xfbs indeed, I also love how simple that is
vivus has left #crystal-lang ["Leaving"]
snsei has quit [Remote host closed the connection]
rohitpaulk has joined #crystal-lang
greengriminal has quit [Quit: This computer has gone to sleep]
<FromGitter>
<xfbs> True that.
greengriminal has joined #crystal-lang
greengriminal has quit [Client Quit]
greengriminal has joined #crystal-lang
ua_ has joined #crystal-lang
ua has quit [Ping timeout: 256 seconds]
greengriminal has quit [Quit: Leaving]
maattdd has quit [Ping timeout: 256 seconds]
ryan_ has joined #crystal-lang
<ryan_>
Hi all, I'm having a problem with trying to get an Array(String) to append a String. I'm getting the following error message though: undefined method '<<' for Char (compile-time type is (Array(String) | Char))
<ryan_>
puts output[0].class # Array(String)
<ryan_>
puts ids.join("#") # String
<ryan_>
output[0] << ids
<FromGitter>
<straight-shoota> so `output[0]` can be `Char` somehow...
<FromGitter>
<straight-shoota> probably because output is `String | Array(String)`
<ryan_>
Hmm
<ryan_>
data = CSV.parse(File.read('file.csv').scrub)