<FromGitter>
<Blacksmoke16> is what i came up with for global events, things that should happen for all routes, just add a trigger annotation to the parent controller class
<FromGitter>
<Blacksmoke16> and will take those and apply them to all routes
<FromGitter>
<Blacksmoke16> also can use it to include common methods, like logging, auth etc that would be accessible to all routes
<FromGitter>
<sam0x17> so I have a bug involving the flate library where it fails to inflate over 16651 bytes UNLESS I allocate 1 GB of memory beforehand randomly
<FromGitter>
<sam0x17> so I'm thinking it may be a GC bug
<FromGitter>
<sam0x17> yes, and as always, people are extremely interested in time estimates involving windows support and multi-threading
<FromGitter>
<Willyboar> well for my scope i don’t understand why windows support is such a big problem
<FromGitter>
<Willyboar> we are in 2019
<FromGitter>
<Willyboar> Neither pythons multi-threading servers supports windows
<FromGitter>
<Willyboar> like uvloop
laaron has joined #crystal-lang
laaron- has quit [Remote host closed the connection]
<FromGitter>
<girng> i posted a long reply to a user on reddit. hope they re-consider crystal
<FromGitter>
<proyb6> Long replies aren’t useful at this point, we need proposal and discussions from community to work on the Crystal implementations and carefully thought out
<FromGitter>
<girng> well, the MT schedulers PR was submitted i think that's really cool
<FromGitter>
<proyb6> Yeah, I thought everyone could discuss MT Scheduler in Crystal forums whether it’s the best way or something we haven’t know yet?
<FromGitter>
<sam0x17> @girng I think the main reason is there are a ton of people (myself included, actually) who would rather do cross-platform desktop apps in crystal than in Node.js or Rust. The second windows supports drops, those apps become financially feasible, which will bring in a lot of interest, attention, and most importantly, developers . That said, I completely agree that windows support makes sense as a post 1.0
<FromGitter>
... agenda item. Multi-threading should be 1.0, and the highest priority right now.
<FromGitter>
<sam0x17> also game development
<FromGitter>
<sam0x17> so in other words, when a language supports windows these days, its to do non web stuff that people nevertheless find very useful
<FromGitter>
<sam0x17> imo
<FromGitter>
<girng> yeah i agree
<FromGitter>
<galvertez> is there no up to date documentation on annotations or am i just not looking in the right place?
laaron has quit [Remote host closed the connection]
<FromGitter>
<galvertez> eh. i'll give it a little more credit than that, but the only real examples of annotations i can find are in JSON::Serializable... those examples aren't bad, but i'm sure they don't teach me everything there is to know about annotations
<FromGitter>
<galvertez> i'm 90% sure annotation solves the problem i'm facing, (and would be by far the cleanest way) but i don't know if the feature i think it has is there. anyway, if there isn't better docs, i'll just have to take another path
<FromGitter>
<galvertez> i'll just ask this... if annotations are even meant to be used on methods in crystal, how would i access those annotations at compile time?
<FromGitter>
<galvertez> is that a thing or was that never the intent of annotations in crystal?
<FromGitter>
<galvertez> trying to write a wrapper method that exposes some other methods without prior knowledge of what they require to operate correctly (the wrapper method sorts that out on behalf of the caller)
<FromGitter>
<Blacksmoke16> Sec
<FromGitter>
<Blacksmoke16> @galvertez
<FromGitter>
<Blacksmoke16> There are two ways
<FromGitter>
<Blacksmoke16> Within the method you could do like `{{@def.annotation(Anno)[:something]}}`
<FromGitter>
<Blacksmoke16> The other way would be like to like iterate over the methods of a class
<FromGitter>
<Blacksmoke16> But off checking if the annotation exists before trying to get values from it
<FromGitter>
<Blacksmoke16> OFC*
<FromGitter>
<Blacksmoke16> Im on my phone ATM, but lookup my GitHub, CrSerializer and Athena are annotation based if you wanted to look through them
<FromGitter>
<Blacksmoke16> I'd be happy to answer any questions
cyberarm has joined #crystal-lang
lagbox has joined #crystal-lang
<FromGitter>
<galvertez> yeah the latter is exactly what i need
<FromGitter>
<galvertez> i couldn't figure out how to iterate over the methods of the class though... tried searching the entire repo and some shards for some examples with every possible search term i could think of and found nothing that worked lol
<FromGitter>
<galvertez> eventually just figured it wasn't implemented and came here to double check
<FromGitter>
<Blacksmoke16> Get list of classes, then c.class.methods
<FromGitter>
<Blacksmoke16> .class for class methods, don't need it for instance methods
<FromGitter>
<Blacksmoke16> There isn't a way to get a list of classes with a given annotation yet, so workaround I'm using is to just get children of a top level class
<FromGitter>
<galvertez> but... is #methods something i can use in a macro? i'm sure i tried that
<FromGitter>
<Blacksmoke16> That's good docs for macros, reference to methods that can be used on a typenode
<FromGitter>
<Blacksmoke16> Yes
<FromGitter>
<galvertez> what the heck
<FromGitter>
<galvertez> i'm like... *really* sure i tried that
<FromGitter>
<galvertez> but apparently i am wrong
<FromGitter>
<Blacksmoke16> :P
<FromGitter>
<galvertez> i mean it was my first idea. "try the 'methods' method - it doesn't work like it does in ruby... but maybe it still works in macros"
<FromGitter>
<galvertez> i guess i still just skipped over it lmao
<FromGitter>
<Blacksmoke16> I guess so
<FromGitter>
<galvertez> thank you man much appreciated
<FromGitter>
<Blacksmoke16> Np
<FromGitter>
<galvertez> thanks to @girng as well :)
<FromGitter>
<girng> eh, i was thjinking of a different annotation i think lol
<FromGitter>
<girng> blacksmoke the MVP
<FromGitter>
<Blacksmoke16> I should write a section in the book about them
<FromGitter>
<Blacksmoke16> Not too familiar with the implementation of them, but pretty good understanding of the usage
<FromGitter>
<proyb6> I also like the know the use case of annotation too, write an article if who are good in it
laaron- has quit [Remote host closed the connection]
<FromGitter>
<Blacksmoke16> Basic they provide a way to attach data to a method, class or property that can be used at complile time
laaron has joined #crystal-lang
<FromGitter>
<Blacksmoke16> MMM Not really
<FromGitter>
<Blacksmoke16> I view them as an alternative to mutable constants
<FromGitter>
<Blacksmoke16> And an easy way to add metadata to things to control how they function behind the scenes
<FromGitter>
<Blacksmoke16> B s
<FromGitter>
<Blacksmoke16> Oops
<FromGitter>
<Blacksmoke16> Example from my link up there would be defining routes from methods with a given annotation, vs using a macro like `get "path" do ` like kemal for example
<FromGitter>
<proyb6> I see, it's useful to reduce the code clutter
<FromGitter>
<Blacksmoke16> Yea, some aren't a fan of the style, but is what it is
_whitelogger has joined #crystal-lang
shmibs has quit [Quit: leaving =o]
shmibs has joined #crystal-lang
shmibs has quit [Remote host closed the connection]
sz0 has quit [Quit: Connection closed for inactivity]
dostoyevsky has quit [Quit: leaving]
gangstacat has joined #crystal-lang
shmibs has joined #crystal-lang
dostoyevsky has joined #crystal-lang
ashirase has quit [Ping timeout: 250 seconds]
<mps>
girng: just read your post on reddit. What that TLA (Three Letter Acronym) WSL mean?
<FromGitter>
<r00ster91> he means the Windows Subsystem for Linux
ashirase has joined #crystal-lang
<mps>
r00ster91: thanks. <grumpy note> why people are lazy to write complete words </grumpy note>
dostoyevsky has quit [Quit: leaving]
<FromGitter>
<girng> ya Windows Subsystem for Linux ty r00ster
dostoyevsky has joined #crystal-lang
<mps>
girng: regarding reddit comments: yesterday I bought book "Crystal programming" (pragprog) because I think and hope that crystal is not 'blind street'
<FromGitter>
<girng> nice. was it a online or hardcover version?
<mps>
I bought because i don't know Ruby and I would have first to learn ruby from some books to understand crystal. So concluded that it will be better to skip that step and jump to learn crystal directly
<FromGitter>
<girng> oh. if that's the case.. i think you made a right decision. i knew zero ruby before i started to dive in with crystal
<mps>
'blind street' looks like is 'blind alley', exactly. That was my wrong literal translation from my head to English the term as is used in my language
<FromGitter>
<girng> it's np yeah i knew what you meant just wanted to double check
<mps>
girng: it is too soon to judge book, but for me looks ok because it will explain some intricacies and 'concepts' of the language which are new to me
<mps>
although, style of writing could be better, IMO
<FromGitter>
<girng> interesting. i'll check out the excerpts later
shmibs has quit [Quit: leaving =o]
shmibs has joined #crystal-lang
<FromGitter>
<proyb6> @Blacksmoke16 @j8r I seem to found a valuable C libraries ⏎ http://www.tommyds.it/
Jenz has joined #crystal-lang
DTZUZO has quit [Ping timeout: 246 seconds]
Jenz has quit [Quit: leaving]
<FromGitter>
<grahamnicholls> @FromIRC @FromIRC
<FromGitter>
<grahamnicholls> A @oprypin Granted. But in this (and in many script cases), I do only have flags only. I still prefer a .each loop around ARGV.reverse to option_parse, though. Just more readable, of course, IMO.
<FromGitter>
<grahamnicholls> OK, so the delete from the array stuff is syntactic, but `debug_mode =ARGV.includes? "-d"` seems super-clear to me.
<oprypin>
ok but it's generally wrong
<oprypin>
like if it ever accepts a file name and i have a file named "-d"
<oprypin>
please use OptionParser :s
<FromGitter>
<bararchy> XD
<FromGitter>
<grahamnicholls> OK, if you have a file called '-d' then frankly you get what you deserve! It does accept filenames - which is what the ARGV.each is supposed to do (after having stripped out the options it understands (-v and -d). But since you ask so nicely, I'll use optionParser. (But the github repo you pointed at kind of illustrates my issue with optionparsers - they tend to be , frankly , convoluted, buggy,
<FromGitter>
... different in every release. But then I'm used to the awful bash versions - which there are at leasat 3 of that I know.
<FromGitter>
<grahamnicholls> How do I get around wanting a global, then? I might even accept your advice, since I'm going to use OptionParser (sigh!)
<FromGitter>
<girng> @grahamnicholls what i do is just wrap my code inside a class, and use like `property debug_mode = false` or w/e
<FromGitter>
<girng> that's how i got out of doing mutable global variables in crystal
<oprypin>
grahamnicholls, using or not using optionparser doesnt change the situation regarding globals
<oprypin>
yes, generally people make a class...
<oprypin>
grahamnicholls, if an attacker makes a file called "-d" do i still deserve it then?
<oprypin>
it is a common practice to wrap command line tools in a function, and it has to be generally usable without any edge cases
<FromGitter>
<grahamnicholls> @oprypin: re globals, that was kind of my point. As for files called '-d' I'm aware of the issue, but as I mentioned on SO, this is a little fun project, rather than something I'm doing for work. If you're an attacker, you have to have my script, access to my system, write permission, etc. If you have those, it's game over anyway.
<oprypin>
grahamnicholls, removing globals from Crystal was not good, people just abose classes and modules instead now
<FromGitter>
<grahamnicholls> I like pragmatic programming languages - which is why I love RUby, rather than Python. Crystal's "YOU CANNOT HAVE GLOBALS" seems a little Pythonic for me. I've lived through various prescriptions for programming - for instance: each function must have only one exit (ugh!), which got replaced with "exit early" which I much prefer. I'm wary of many absolute restrictions like this one.
<FromGitter>
<girng> i just adapt to it and reap the benefits later. they will def outweigh the negatives
<FromGitter>
<girng> i was like you graham when i first started crystal, but a lot more raged. i wanted to quit after i read issues on github of them removing global variables (used to be a thing). but i am DEF glad i did not. would have been a very bad mistake for me
<FromGitter>
<Blacksmoke16> north west about 40min, around beaver
<FromGitter>
<grahamnicholls> Hey thanks, all. Looking at those now. PS @girng I do agree - ruby-like syntax with compiled is compelling - like go but better syntax. I love all the devops tools we now have, like ansible, terraform, etc, which are all single binaries. You expect an installer, but it's just a binary; put it in the PATH, and you're good to go.
<FromGitter>
<grahamnicholls> Java is responsible (IMO) for so much utter cr*p we've ended up with - every program has its (usually incompatible dependencies - ugh!)
<FromGitter>
<girng> never used Java before, and don't think i will ever hahaha
<FromGitter>
<grahamnicholls> Hello world! is 100k (of source). Ok I exaggerate, but I loathe it.
<FromGitter>
<grahamnicholls> PS @oprypin, TVM!
<FromGitter>
<girng> java is actually the only language i never tried. i tried golang, javascript, erlang, elixir, c++, rust, julia but keep coming back to crystal
<FromGitter>
<girng> oh, and nim
<FromGitter>
<grahamnicholls> interesting - I keep coming back to Ruby
<FromGitter>
<grahamnicholls> Lua is nice - used to be a Lua dev.
<FromGitter>
<grahamnicholls> fast
<FromGitter>
<girng> oh yeah lua too. well i fiddled around with love2d, but yeah my top would be LuA and Crystal
<FromGitter>
<girng> syntax wise, i love them
<FromGitter>
<girng> @grahamnicholls so you were a rubyist for quite some time and found crystal?
<FromGitter>
<grahamnicholls> Hmm. FOr me it'd be Ruby (not enough experience with Crystal yet), and C, maybe, although that's a bit old-school now.
<FromGitter>
<girng> i tried c and made a tcp gameserver with a tickrate. i followed a lot of thechernoproject's tutorials online. unfortunately, went back to crystal cause so much more simpler for me. especially linking mysql connector and stuff. was so much trouble in C compared to just doing require "db" and --static on export..
<FromGitter>
<girng> crystal makes it very, VERY easy
<FromGitter>
<grahamnicholls> Well, I'm a devops engineer, so I use whatever I have to, but I prefer Ruby - it's just so expressive.
<FromGitter>
<girng> very cool. i actually never even used ruby before i found out about crystal lol
<FromGitter>
<Blacksmoke16> now comes the fun part of writing all the docs :3
<FromGitter>
<girng> O_O
<FromGitter>
<Blacksmoke16> hehe
Raimondi has joined #crystal-lang
<FromGitter>
<Blacksmoke16> is there a way to detect that two methods have the same name in a class
Raimondi has quit [Ping timeout: 240 seconds]
<FromGitter>
<Blacksmoke16> is there a reason you cant have abstract class defs in an abstract class?
Raimondi has joined #crystal-lang
sagax has quit [Ping timeout: 246 seconds]
Vexatos has quit [Remote host closed the connection]
Vexatos has joined #crystal-lang
spacemanspam has joined #crystal-lang
dostoyevsky has quit [Quit: leaving]
dostoyevsky has joined #crystal-lang
<FromGitter>
<grahamnicholls> BTW, @oprypin, I'm confused, re your comment regarding a file called '-d' - with my method of handling the command-line, even if it were generated by a shell glob, the program would read it as an option, and switch on debug - where's the attack vector (since they could always run with '-d' anyway)? PS I've just moticed your comment re removing globals, and have to say that I agree. Anyway, I'll still
<FromGitter>
... persevere for a while with optionparser ...
<FromGitter>
<r00ster91> I don't understand the difference between String#byte_index and String#index. Does anyone know the differences? The methods seem to be behave identical.
<oprypin>
r00ster91, try a string with non-ascii characters. "приклад"
<oprypin>
grahamnicholls, well sure, this particular program likely doesn't have any such attack vectors. still no reason to be sloppy
<FromGitter>
<r00ster91> ooh byte_index seems to behave weirdely with non-ascii characters, thanks! Will use index in that case
<oprypin>
grahamnicholls, the point is if that flag was doing something really nasty and you exposed this program somewhere, letting the user enter only a file name
<oprypin>
but even without a real hack it could be annoying
<oprypin>
btw to prevent that you'd write `./my_program -- "$filename"` which your custom handler doesn't support
<oprypin>
thus violating some POSIX spec
<oprypin>
(which, again, not many people care about, but why be sloppy)
<FromGitter>
<fridgerator> when linking a c lib on linux with an .so file that is not in the system path, how do you link to it? I tried `@[Link("libname", ldflags: "-L/path/to/libname.so")]` but this doesn't seem to work
<oprypin>
fridgerator, -L accepts a directory that should be added to path
<FromGitter>
<fridgerator> oh right, yeah i'm using the path not includeing the so filename
<FromGitter>
<fridgerator> I get `error while loading shared libraries: libname.so: cannot open shared object file: No such file or directory`
<FromGitter>
<fridgerator> even though the path exists and libname.so is in there
<oprypin>
what exactly is libname
<FromGitter>
<fridgerator> libcef.so
<oprypin>
so do you have this in code? `Link("cef`
<FromGitter>
<fridgerator> libcef.so is in the Release dir
<FromGitter>
<fridgerator> kk
<oprypin>
fridgerator, there's some way to make crystal produce the command that it attempts during linking. maybe that even happens by default for an error. could you copy that?
<oprypin>
does it manage to produce any executable?
<FromGitter>
<fridgerator> nope, just stops on error
<oprypin>
bah
<FromGitter>
<fridgerator> I suppose I'll just try adding the path to my system path
<oprypin>
it can happen that loading that file works fine but its dependency is missing
<FromGitter>
<fridgerator> ah ok
<oprypin>
u can try `export LIBRARY_PATH=...` but that's equivalent to `-L`
<oprypin>
im not sure how to makee it say what dependency is missing if there is no executable
<FromGitter>
<fridgerator> same thing
<FromGitter>
<bararchy> ldd the `.so` file? :)
<FromGitter>
<fridgerator> let me try that
spacemanspam has quit [Read error: Connection reset by peer]
<FromGitter>
<fridgerator> not seeing any "not found" in the output
<FromGitter>
<fridgerator> oprypin after setting `LD_LIBRARY_PATH` it works
<oprypin>
but you said it didnt produce any executable, which, in my understanding, conflicts with that
<FromGitter>
<kingsleyh> @fridgerator did you get it working? I've recently been working on C bindings and had to play around with the LD stuff
<FromGitter>
<fridgerator> yeah its working now, there is some other error now but its unlreated to this binding
<FromGitter>
<kingsleyh> ok cool :)
rocx has joined #crystal-lang
DTZUZO has joined #crystal-lang
<FromGitter>
<talbergs> Hi, the crystal db lib confuses me. It provides many ways to cast to types. But what to do if I do not know the type before hand? ⏎ ` pp! Store.db.query_all "select * from `#{t.desc.table_name}` limit 2;", as: Int64` ⏎ It may toss runetime exception on me. ⏎ I'd like to know the type I got from db, then decide. Else it just gives me (Any|Type) stuff. Did I miss something?
<FromGitter>
<Blacksmoke16> prob better to use an ORM
<FromGitter>
<talbergs> The point is I do not know the types before hand
<FromGitter>
<talbergs> It is going to be a database browser client
Raimondi has quit [Ping timeout: 240 seconds]
<FromGitter>
<talbergs> Anybody confirms that verbose approach to "test for type" is the way to go?
<FromGitter>
<Blacksmoke16> but you should know the types since its a table, the types are static on the columns
<FromGitter>
<Blacksmoke16> so like if you're viewing a table with the data from users, you would know that name would be string, or user_id would be Int32 etc based on the typing of the columns
<FromGitter>
<fridgerator> I think he's saying it could be used on any database, with any tables
<FromGitter>
<Blacksmoke16> ah i see
<FromGitter>
<kingsleyh> maybe could ask the db for the types
<FromGitter>
<kingsleyh> get the db table schema with all the tables and types
<FromGitter>
<girng> you have to know the types beforehand, it's the column in MYSQL
<FromGitter>
<Blacksmoke16> @vladfaust just for you
<FromGitter>
<fridgerator> does result_set have `is_a?` ?
<FromGitter>
<vladfaust> @Blacksmoke16 first of all, good job! Writing docs is tough and you did it 🎉 You got my star 😉 ⏎ I'm curious how you'd implemented `"/add/:val1/:val2"` routes? AFAIK Luis'es Radix tree does not support that
<FromGitter>
<Blacksmoke16> that doesn't work, as the first route gets ownership of it
<FromGitter>
<Blacksmoke16> is possible in future to maybe look into doing some magic to take into consideration the type of the param when route finding
<FromGitter>
<Blacksmoke16> would be like over loadable routes haha
<FromGitter>
<girng> @talbergs are they all Strings types?
<FromGitter>
<girng> @talbergs try to just write out the field names in the query instead of doing `*`
<FromGitter>
<Blacksmoke16> like would match `/users/foo` and not `/users/bar`
<FromGitter>
<vladfaust> That's neat indeed
<FromGitter>
<Blacksmoke16> but good call, have to see if i can use that for routing, like if it doesnt match the found route, find another?
<FromGitter>
<vladfaust> IDK
<FromGitter>
<malkomalko> what's the best way to test for an abstract type? I have a `Hash(String, AbstractClass)` where the items are all subclassing `< AbstractClass` but it complains that it doesn't work.
<rocx>
`thing.is_a?(AbstractClass)` ?
<FromGitter>
<malkomalko> well, it won't compile, I'm getting something like `no overload matches 'Hash(String, FlutterOpml::Templates::WidgetTemplate)#[]=' with types String, FlutterOpml::Templates::StatefulWidget.class`
<FromGitter>
<malkomalko> oh, it looks like I added `} of String => WidgetTemplate` but didn't need to
<FromGitter>
<grahamnicholls> @Blacksmoke16 , @oprypin I've updated my SO question with an answer, which does use a module, (and (sigh!) OptionParser ) - is thata reasonably Crystalline?
<oprypin>
grahamnicholls, you have 4 out of 5 close votes on the question :s
<FromGitter>
<grahamnicholls> Oh good grief, why?
<oprypin>
it's just really open ended or at least it appears very much so
<rocx>
"rar globals bad! *hiss*"
<FromGitter>
<talbergs> @girng Thank you, but this wouldn't be helpful, seems you misunderstood my inital problem there - I do not know the types that are about to be returned before hand. Yes i know the fields "i have TableStructure" array of them named in key "Field" there. That "TableStructure" is a structure that i get by querying information_scheme - there I do know types and fields before hand. But once user selects any
<FromGitter>
... random of his tables - i want to be able to render some preview for that user
<FromGitter>
<grahamnicholls> PS a confession - I dislike SO more than I hate optionParser!
<oprypin>
it's really not a useful site at this point
<FromGitter>
<grahamnicholls> Yes, and not all upvoted answers are the best ones. Things become accepted wisdom. (like "change your passwords every 90 days, which is (thankfully less so) the percieved wisdim, but largely wrong.
<oprypin>
grahamnicholls, i dont know if you noticed but i also included a good use of logging/verbosity in my earlier example
<FromGitter>
<grahamnicholls> @oprypin Thanks - I'll look there - and yes, your logger use did spark thought - I kind of went "of course"
<oprypin>
yes this is kinda abusing modules but that's what you gotta do under this silly constraint
<rocx>
quick question about namespacing though it may just be more of a general software one: say i have a class Task1 (because this is a challenge based on tasks 1..25) but it involves another class Thing. but here's the problem: another Task class will have its own Thing. how can i properly keep these things separate besides "hurr modules"?
<oprypin>
first of all `class Task1` sounds like it shouldn't be a class
<oprypin>
why are you concerned that (presumably) completely separate programs have something that's named the same?
<rocx>
oprypin: that's what i'm trying to figure out around: because they all have an input that would be better off parsed and strucutred the one time upon Task1's initialization.
<rocx>
so guess your point is to just instead of trying to make these all separate programs?
<oprypin>
yes, i'd strongly recommend that
<FromGitter>
<grahamnicholls> Thanks all, and goodnight.
<oprypin>
rocx, in fact, i'd even recommend against sharing code between part a and b
<oprypin>
each of them makes sense and the diff can be cute too
<rocx>
guess that makes sense. the only reason i was trying to keep them a single program is a "wrapper" where i can just call `./myprog -t1 <input.txt` and get the output from that.
<oprypin>
input / output is like 3 lines
<oprypin>
stuff like `File.each_line("input.txt")` and `puts`
<rocx>
it's less of the input/output, more about all the parsing on those lines.
<rocx>
but yeah, guess i could just do TaskX modules with a self.part1 and self.part2 and see how that goes. thanks.
<oprypin>
but why do modules?
<oprypin>
what prevents you from just writing code directly?
<rocx>
like a script instead of a full-blown program?
<oprypin>
i guess
<rocx>
practice.
<oprypin>
practice what, typing `module Task1`, `self.`, `Task1.` a bunch of times?
<rocx>
"software engineering".
<oprypin>
"java"
<rocx>
yeah that sounds as disgusting as it felt coming out but that's what we're being taught as our bloody degree.
<rocx>
basically training myself to manage other peoples' mental gymnastics.
<oprypin>
that's BS alright
<rocx>
indeed.
<rocx>
heck, my mentor who teaches the curriculum's final project is all "there's no such thing as a frontend and backend distinction, it's just web development now".
<rocx>
so the quality of my education may be very much questionable.
<oprypin>
yeah it usually is
<oprypin>
but you came here so that's already something
<rocx>
i'm learning something that isn't java so that's already something.
<rocx>
(to be honest, ruby's pretty nice too but the lisp-like type system? static types just make it easier)
<oprypin>
ah you your curriculum *is* java. guessed that without intending to
<rocx>
correct.
<rocx>
there's a python class but it's an elective for our "software development" majors and is required for our "data science" majors.
<oprypin>
tbh java isn't even that bad, i just dont like that they put everything into classes
<rocx>
that or how verbose it is.
<rocx>
crystal's nilable types make for a better Optional<T>. heck, you can even safely check arrays with Array#[]? and deal with that in an if/when/unless block.
<oprypin>
yes, that is an area where crystal is very far ahead of literally everything else