ChanServ changed the topic of #crystal-lang to: The Crystal programming language | | Fund Crystal's development: | GH: | Docs: | Gitter:
<FromGitter> <> Maybe bad design, or maybe an edge case that only deserves a hack...idk
<FromGitter> <Blacksmoke16> whats the method?
<FromGitter> <Blacksmoke16> if you truly want to prevent it, could override it and do like `{% raise "Some message saying it doesn't exist" %}`
<FromGitter> <> Well first, my class hierarchy looks like `Aggregate (abstract) -> Vector (abstract) -> Vector2D | Vector3D | Vector4D`. Aggregate contains shared functionality common to all aggregate types (vectors, matrices, and quaternions). Vector contains things common to all vector subtypes.
<FromGitter> <> Aggregate contains a few `self.rand` class methods that create the type with each of its elements a random value within some range.
<FromGitter> <> Which is perfectly fine for vectors and matrices, but for quaternions, does not make sense in the field of 3D graphics. It is an math problem to ever have an un-normalized quaternion.
<FromGitter> <Blacksmoke16> this may be a good usecase for a module. `Randomizable`
<FromGitter> <Blacksmoke16> as also remember modules can be used to type check
<FromGitter> <> Hmm, I'm not sure how to do that for this tbh
<FromGitter> <Blacksmoke16> so could have overloads specific to that module, or `obj.is_a? Randomizable` etc
<FromGitter> <> Type checking with modules is new to me, but I'll look up how to do it later
<FromGitter> <> First time using enums and `case`. Is this method good style-wise? `Space` is an enum with 2 variants that will be needed for a few methods: ⏎ ⏎ ```code paste, see link``` []
<FromGitter> <Blacksmoke16> you can do `in .local?` and `in .world?`
<FromGitter> <Blacksmoke16> and im assuming you know about enum autocasting?
<FromGitter> <> didn't know they are defined
<FromGitter> <> no i dont
<FromGitter> <Blacksmoke16> `space : Origin::Space = :local`
<FromGitter> <Blacksmoke16> can use symbols to autocast to enum members
<FromGitter> <> The docs say not to use symbols
<FromGitter> <Blacksmoke16> this is what symbols should be used for
<FromGitter> <> Oh, maybe I was confused by ⏎ ⏎ > The recommended thing to do is to use enums whenever possible, only use ⏎ symbols for the internal implementation of an API, and avoid symbols for ⏎ public APIs. []
<FromGitter> <Blacksmoke16> well thats also true, you shouldnt use symbols at all imo, except as a means to autocast to enum members
<FromGitter> <> Ok, I'm honestly clueless about all of this. I assume casting is a compile-time process?
<FromGitter> <Blacksmoke16> yea, its the same feature that allows passing like `2` to a method thats typed as `Int64`
<FromGitter> <Blacksmoke16> versus needing to do `2_i64`
<FromGitter> <> Ok. Any way to remove the need to normalize both branches? I'm going to have similar code for other enums with more variants
<FromGitter> <> Just trying to figure a nice and concise way to do this generally
<FromGitter> <Blacksmoke16> can you do like `def *(other : Origin::Space)` on `self`
<FromGitter> <Blacksmoke16> then the opposite on the other one
<FromGitter> <Blacksmoke16> oh, what if you call `.normalize` on the `end` of the case?
<FromGitter> <Blacksmoke16> ```code paste, see link``` []
<FromGitter> <> Could do the latter. Btw:
<FromGitter> <> ```code paste, see link``` []
<FromGitter> <Blacksmoke16> `.local?`
<FromGitter> <> oh oops
<FromGitter> <Blacksmoke16> `Enum` type automatically generates these methods for each member
<FromGitter> <> I have other issues to fix in order to see how this works. a constructor not existing when I think it should be...ugh
<FromGitter> <Blacksmoke16> :(
ur5us has joined #crystal-lang
<FromGitter> <> ```code paste, see link``` ⏎ ⏎ 🤔 []
<FromGitter> <> Oh
<FromGitter> <> wait the error is different
<FromGitter> <Blacksmoke16> i think you should pareans
<FromGitter> <Blacksmoke16> parens
<FromGitter> <Blacksmoke16> ```new( ⏎ (w * other.w - x * other.x - y * other.y - z * other.z), ⏎ ... ⏎ )``` []
<FromGitter> <Blacksmoke16> might help
<FromGitter> <> precedence rules are pretty clear there. Why do you like Lisp so much :)
<FromGitter> <Blacksmoke16> heh
sevvie has joined #crystal-lang
<FromGitter> <> Interesting. So Crystal/Ruby don't consider exponentiation common enough to have a `^` operator as a keyword and relies on the stdlib?
<FromGitter> <Blacksmoke16> pretty sure you can do **
<FromGitter> <> Ok nice.
ur5us has quit [Ping timeout: 240 seconds]
<FromGitter> <> Welp, knew this would occur sooner or later
ur5us has joined #crystal-lang
<FromGitter> <> First time the whole "methods belong to types" scheme is giving me some design problems.
<FromGitter> <> Quaternion separation of concern should have a `from_matrix` (matrix -> quaternion), and a `to_matrix` (quaternion -> matrix) well as a few other symmetrical conversion routines where the receiver is not an instance of its class.
<FromGitter> <> I guess this isn't a problem is Crystal, since I believe its parser has cycle detection
<FromGitter> <> I mean I can just have mutually dependent files (`matrix#to_quat` + `quat#to_matrix`) and have the compiler figure it out.
<FromGitter> <> mutually dependent files really annoys me in Lisp, but I suppose that's normal around here with single dispatch
<FromGitter> <Blacksmoke16> thats the way you would do it yea, not really a way around it
<FromGitter> <Blacksmoke16> it's common, like for String there is `.to_slice`
<FromGitter> <> I think the way I would do it actually is to define new method overloads for conversions
ur5us has quit [Ping timeout: 240 seconds]
<FromGitter> <> `.new` that is
<FromGitter> <Blacksmoke16> versus `#to_matrix` defined on the `quat` type?
<FromGitter> <> Yeah, because some things don't have a first class type.
<FromGitter> <> Like, there is a quat.to_axis_angle and quat.from_euler_angles in my other library, both are vec3's...
<FromGitter> <> These math types are pretty abstract and depends on how they are used what they actually represent
<FromGitter> <> in some cases anyway
<FromGitter> <> So having a ` : Vector3D, angle :Float64)` for "from axis-angle" and ` : Vector3D)` for "from Euler angles" makes more sense to me (and vice versa under the vec3 type)
<FromGitter> <Blacksmoke16> hmm
<FromGitter> <> Just realized it won't work anyhow
<FromGitter> <Blacksmoke16> oh?
<FromGitter> <Blacksmoke16> i also wonder sometimes when to use general `.new` versus a more specialized name
<FromGitter> <> quat from axis angle and quat from velocity both take a vec3 and float
<FromGitter> <Blacksmoke16> like a little lib im working on now i have `.from_file_path` and `.from_io` versus an overloaded `.new` for each thing
<FromGitter> <Blacksmoke16> you could do something like that then, `.from_vector angles, float`
<FromGitter> <> I say `.new` is a good choice when its unambiguous unlike the above.
<FromGitter> <> but that opinion has exceptions of course. like for basic types, i do agree with the explicit to_a, to_s, etc
<FromGitter> <Blacksmoke16> also not sure if you picked up on it, but `.` means a class method and `#to_a` would be instance yea
<FromGitter> <> of course i did :)
<FromGitter> <Blacksmoke16> 👌
<FromGitter> <> i just assumed you `.from_file_path` was an instance callsite, not the notation for a class method
<FromGitter> <Blacksmoke16> no, it's a constructor, just not named `.new`
<FromGitter> <Blacksmoke16> like part of me thinks passing whatever to `.new` is a nicer API, but it reads better having the named constructors
<FromGitter> <> ok. i admit it is a little ambiguous when talking about == == obj foo, when .foo on its own means the definition of .foo
<FromGitter> <Blacksmoke16> well `.foo` would be assumed to be a class method on some type
<FromGitter> <Blacksmoke16> but when used in conjunction with an object its more clear it's most likely an instance method call
<FromGitter> <Blacksmoke16> well not entirely true as `obj` could be some `SomeType.class`
<FromGitter> <> Sure I'm just saying `Math#sqrt` can be called as `Math.sqrt 16`
<FromGitter> <> so it can get confusing when talking about class vs instance methods for me sometimes :)
<FromGitter> <Blacksmoke16> well in *that* case i would be assumed that it more like ``
<FromGitter> <Blacksmoke16> would need to know that its a module that `extend self` as to why it can be called as a class method
<FromGitter> <> am i doing things wrong everywhere then?
<FromGitter> <Blacksmoke16> in what regard?
<FromGitter> <> Latest function written: ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ `.x`, `.y`, and `.z` are ivar accesses. `.sin` and `.cos` are instance methods, etc []
<FromGitter> <Blacksmoke16> sorry to be clear, the diff between `.method` and `#method` is mainly intended for like docs and stuff
<FromGitter> <Blacksmoke16> you use dot notation to call both types in practice
<FromGitter> <> Yes that's what I originally assumed. Ok, I was good then
<FromGitter> <> You scared me :)
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <> So yeah, I think I will use `.new` in this math library *only* when it is very clear (to someone familiar with the math anyway...which should be all users of this library), from the call site argument types what will; only 1 thing can happen when calling a quat class method given a mat3
<FromGitter> <> I think it would be clearer and more concise that way, and only using explicit conversion methods when it is not completely obvious, or there is a overload conflict
<FromGitter> <> But this is all a joy having this available over what I'm used to
<FromGitter> <> In Lisp, there is only (usually slow) runtime dispatching for generics, and you cannot overload arity or optional argument types....only required positional argument types...and all methods need to have the same arity. If you want much faster speed, you have to use regular functions and ditch generics, which means either scary macros to do something like this math library, or lots of DRY violations
<FromGitter> <> The only languages I've used or had to read lots of that have generics are: ⏎ ⏎ 1) Rust (no thanks, not worth the development time and noisy syntax) ⏎ 2) Nim (generics are a little complex and signatures are line noise, and compiler is buggy) ⏎ 3) C# (way too verbose) ... []
<FromGitter> <> excluding Lisp of course, and this was a major factor why I decided to start learning it last week
<FromGitter> <Blacksmoke16> to be fair Crystal generics are quite buggy in their own right
<FromGitter> <Blacksmoke16> mainly when you start to introduce inheritance and stuff
<FromGitter> <> I wouldn't doubt it, as there usually is with static languages, but I haven't seen any yet in my simple inheritance use.
<FromGitter> <> I like Crystal a lot because it is simple, not because it's bug-free. I have most of the docs in memory and code is easy to read and understand. I think it's like the polar opposite of template-heavy C++ (or most any for C++ for that matter).
<FromGitter> <Blacksmoke16> i also like that the stdlib and stuff is crystal
<FromGitter> <Blacksmoke16> so its easy to dive into a stdlib method to see what its doing
<FromGitter> <Blacksmoke16> versus needing to decipher C if you wanted to do that with PHP or Ruby
<FromGitter> <> If any software developer thinks their code is bug-free they need to += user_count or fix their fuzzer.
<FromGitter> <Blacksmoke16> cant have any bugs if you dont write any code ;)
<FromGitter> <Blacksmoke16> :bigbrain:
<FromGitter> <> Plus, Crystal has garbage collection
<FromGitter> <> semi-related:
<FromGitter> <Blacksmoke16> well PHP and Ruby do too
<FromGitter> <Blacksmoke16> its not that uncommon
<FromGitter> <> It shouldn't be. Lisp invented it in the 50's :)
<FromGitter> <> So for the non-`.new` methods that require explicit naming, I'm torn on a `self.from_axis_angles(axis : Vec3, angle : Float64)` class method on the Quat type, or a `to_quat` instance method on the Vec3 type.
ur5us has joined #crystal-lang
<FromGitter> <> The convention seems to be to_* instance methods but dunno. I'll sleep on it / wait on a suggestion. night
ur5us has quit [Remote host closed the connection]
ur5us has joined #crystal-lang
ur5us has quit [Ping timeout: 272 seconds]
<FromGitter> <HertzDevil> getting ready for crystal-lang/crystal#3457
<FromGitter> <> mfiano ( i don't see `to_` method as being appropriate even multiple args are involved
<FromGitter> <> and generally i view it as much more narrowly applicable: *conversions* where there's only 1 obvious way to convert between the two things
<FromGitter> <> I don't think anyone was arguing about multiple arguments being involved'
<FromGitter> <> > `self.from_axis_angles(axis : Vec3, angle : Float64)` ⏎ ⏎ ? that's multiple args
<FromGitter> <HertzDevil> yeah like `Int#to_s`
<FromGitter> <> the question wasn't whether to use it or not because it has multiple args
<FromGitter> <> so im saying don't use to_
<FromGitter> <> > yeah like `Int#to_s` ⏎ ⏎ that has one thing to be converted just with some tweaks. so, multiple args but not in the same way
<FromGitter> <> I believe a new method should be used if it is obvious what it is doing given the problem domain expertise. in cases where it's not so obvious or there are method signature overloading conflicts, a `to_` or `from_` may be appropriate.
<FromGitter> <> In mathematics a quaternion can be computed given a real part and imaginary part scalars, or it can be transformed from some intermediary representation, such as a rotation matrix, transformation matrix, a 3d axis/angle representation, or a set of Euler angles. The first and the last 2 of those are multiple arguments.
<FromGitter> <> I think a class method is always better equipped to look obvious compared to `to_{abbreviated}`
<FromGitter> <> I do agree about the abbreviated part. I am always in favor of self-documenting code (in addition to inline and offline documentation of course).
<FromGitter> <> Quat.from_real_and_imag what's the issue
<FromGitter> <> you mentioned about overloads possibly being a problem. but then you just avoid overloads and give full names
<FromGitter> <> That is the canonical description of a quaternion and should therefor be the probably only .new constructor.
<FromGitter> <> makes sense
<FromGitter> <> The thing is, these types of decisions don't have to be made in languages with multiple dispatch such as Common Lisp and Nim and many other languages that I'm used to.
<FromGitter> <> Methods do not belong to classes in those languages, so I am just adjusting :)
<FromGitter> <> in Nim i haven't seen that as a significant distinction. the fact that you have the option to call it as a method or not isn't significant because one of the two ways will usually be defined as frowned upon. and for the other advantage - ability to add more methods later - Crystal has a different way
<FromGitter> <> It'll take some time for me to get used to not having this type of freedom Lisp provides (and other types), after having used it almost exclusively for a couple decades, but I am not complaining.
<FromGitter> <> Multiple dispatch is very useful for game development and physics simulations in particular. I will have to find new solutions to very old algorithms of mine.
<FromGitter> <> I really appreciate all the great advice around here. I have been looking for a language that clicks with me for a couple years now.
ua_ has joined #crystal-lang
<FromGitter> <pyrsmk> I was too, and it does not deceive me!
<FromGitter> <pyrsmk> maybe apart of macros that are really complicated to debug when something goes wrong
<hightower4> when that happens you can put {% debug %} into the macro code and it will print you the expanded macro
<FromGitter> <> There's nothing special about macros. They are just functions, just like methods :)
<FromGitter> <> The only difference is the time they are evaluated.
<FromGitter> <> and I suppose in Crystal's case, use a DSL rather than the host language
<FromGitter> <pyrsmk> @hightower4 I know, but this is clearly not enough when you're not dealing with code generation mistakes but bugs that come from types, the compiler tends to raise an error that is not really informational because it fails at locations that are not directly related to the issue, or complicated to understand
<FromGitter> <pyrsmk> in those cases, you need to reduce your code and watch if the error is different and clearer, or if you can isolate the problem by commenting the code around, etc...
<FromGitter> <pyrsmk> yes, this is not easy at first to clearly understand when code parts are executed
<FromGitter> <pyrsmk> (FYI that's not the first time I write macros ^^)
<FromGitter> <> oprypin ( You are familiar with Nim?
<FromGitter> <> mfiano ( yea like 5 years ago i left it
<FromGitter> <> I am sitting here wondering how to convert this function over
<FromGitter> <> This signature is weird. I don't know how I came up with this a couple years ago. It takes a variable number of 2-tuples
<FromGitter> <> Wondering how to best map that to Crystal
<FromGitter> <> mfiano ( as a variable number of 2-tuples i guess
hightower4 has quit [Ping timeout: 265 seconds]
<FromGitter> <> or as an Enumerable of 2-tuples. probably better. because crystal generates a separate function body for each combination of args
<FromGitter> <> Hmm. That might be a job for tomorrow...sounds above my abilities right now :)
<FromGitter> <> : Enumerable({Type1, Type2})
<FromGitter> <> no difficulty at all
<FromGitter> <> What does a call site look like?
<FromGitter> <> f([{a, b}, {c, d}])
<FromGitter> <> I see now. Thanks.
<FromGitter> <> I should get to bed before I ask anymore dumb questions. Thanks everyone.
iskra has quit [Ping timeout: 252 seconds]
iskra has joined #crystal-lang
ur5us has joined #crystal-lang
ur5us has quit [Client Quit]
szutt has joined #crystal-lang
<FromGitter> <> Is not being able to invoke the `[]?` method via implicit-object syntax an intentional behavior within the case expression?
<FromGitter> <HertzDevil> you do it by `when .[]?(...)`
<FromGitter> <> Ah thank you!
<FromGitter> <Uzay-G> hello, i'm a beginner with crystal and was wondering what the best way to do this is: I have two functions: ```
<FromGitter> <Uzay-G> I'm getting ```If you declared 'var' in a suffix if, declare it in a regular if for this to work. If the variable was declared in a macro it's not visible outside it)```
<FromGitter> <Uzay-G> so i assume this isn't possible, but is there any other way to accomplish something similar?
<FromGitter> <> @Uzay-G: regardless if it's a macro or not, make the helper return those values and use multiple assignment
<FromGitter> <> a, b, c = my_helper()
<FromGitter> <> macros intentionally don't let new variable names escape them
<FromGitter> <Uzay-G> ah ic
<FromGitter> <Uzay-G> for multiple assignment do i return the variables I want at the end of the helper?
<FromGitter> <> yes
<FromGitter> <Uzay-G> thanks!
hightower4 has joined #crystal-lang
avane has quit [Ping timeout: 268 seconds]
avane has joined #crystal-lang
szutt has quit [Ping timeout: 246 seconds]
szutt has joined #crystal-lang
<FromGitter> <Uzay-G> is there any equivalent of `defined?` in ruby (checks if a variable exists) for crystal?
szutt has quit [Ping timeout: 246 seconds]
szutt has joined #crystal-lang
<raz> can a macro discover the name of the method from which it gets called? `macro foo; end ... def bar; foo; end` <- any way to get a "foo" inside the macro?
<FromGitter> <HertzDevil> i assume you mean getting `bar` because it is `bar` that calls `foo`
<FromGitter> <HertzDevil> ```code paste, see link``` []
<raz> apologies, indeed bar was meant
<raz> aw, that's sweet! right... i think i've even used that before and then promptly forgotten about it
szutt has quit [Ping timeout: 246 seconds]
szutt has joined #crystal-lang
szutt has quit [Ping timeout: 246 seconds]
szutt has joined #crystal-lang
ming has joined #crystal-lang
Nik- has joined #crystal-lang
<FromGitter> <Blacksmoke16> when binding a c file that is locally defined, does it matter if you link to like hello.c versus hello.o? Both seem to work
<FromGitter> <> @Blacksmoke16: I don't think you can technically link to a source file, as it's just text and doesn't have the kind of structure an object file does, so linking to hello.c probably just produces the object file and links to that.
<FromGitter> <Blacksmoke16> and i imagine it's better to link directly to the .o file you build beforehand?
szutt has quit [Quit: Client closed]
hightower4 has quit [Ping timeout: 255 seconds]
<FromGitter> <> I don't know, I guess I'd ask: better by what measurement? It would probably be more resource-efficient, but also introduces an opportunity to link to a stale object.
<FromGitter> <Blacksmoke16> fair enough
<FromGitter> <Blacksmoke16> probably also allows you to use better optimizations and such
rem has joined #crystal-lang
ming has quit [Ping timeout: 240 seconds]
ming has joined #crystal-lang
<FromGitter> <> Hmm, fully-qualified enum variants are a pain in some public APIs. I'm not sure what else I should use here though
<FromGitter> <Blacksmoke16> hm?
<FromGitter> <Blacksmoke16> you mean like `some_method My::App::Foo::Color::RED`?
<FromGitter> <> cr ⏎ ⏎ ```(quat:orient :local :y 0.5 :z 1.4 :x 2.2)``` []
<FromGitter> <Blacksmoke16> remember what i was saying yesterday? `[{:y, 0.5}, ...]` pretty sure that should work
<FromGitter> <> Oh I thought that was only acceptable because it was in the `case` and not part of the public API like the docs frown upon
<FromGitter> <Blacksmoke16> should be valid to any argument accepting an enum type
<FromGitter> <HertzDevil> no the tuple itself is not a direct argument so autocasting won't work like that
<raz> mjfiano: agree. in some cases you can use the symbol shorthand. but they become a pain esp. when you try to pass them around somehow :(
<FromGitter> <Blacksmoke16> :sad:
<FromGitter> <> So I guess the solution is to not use an `Enumerable` and use a varargs 2-tuple, similar to lisp
<FromGitter> <> If I understand @HertzDevil
<FromGitter> <HertzDevil> that doesn't work either
<FromGitter> <Blacksmoke16> you could support both if you wanted
<FromGitter> <Blacksmoke16> but sounds like you'll just have to use the FQN of the enum member in this context :(
<FromGitter> <HertzDevil> can't they be optional named parameters
HumanG33k has quit [Ping timeout: 252 seconds]
<FromGitter> <> No they can't be
<FromGitter> <> Repeating an axis is allowed.
<FromGitter> <HertzDevil> you can do this though
<FromGitter> <HertzDevil> ```code paste, see link``` []
<FromGitter> <> Oh, clever
<FromGitter> <> The only problem is that forces me to move the optional last argument (not shown in the call above) to a required first argument (I think)
<FromGitter> <> Which may not be that big of a problem
<FromGitter> <Blacksmoke16> if you add it to the end it would just be required to be provided as a named arg
<FromGitter> <HertzDevil> ^
<FromGitter> <> Ok that works good then. Thanks!
<FromGitter> <HertzDevil> and for the people who really hate `NamedTuple`s: ⏎ ⏎ ```code paste, see link``` []
<FromGitter> <> Yeah, no :)
<FromGitter> <HertzDevil> they should have the same runtime costs btw (except these records are mutable)
<FromGitter> <Blacksmoke16> `record` only generates getters so they shouldn't be
<FromGitter> <HertzDevil> oh does it
<FromGitter> <Blacksmoke16> ye
<FromGitter> <> ⏎ ⏎ Are you sure about that signature? The docs seem to indicate that is the value syntax, not the type syntax
<FromGitter> <HertzDevil>
<FromGitter> <> Is that a docs mistake or am I just parsing it incorrectly?
<FromGitter> <> The latter. I see now
<FromGitter> <> Ah I don't know if your idea will work after all
<FromGitter> <> ```code paste, see link``` ⏎ ⏎ This is the code. I need to iterate over the args and unpack them in the block []
<FromGitter> <> I guess the question is how can i map over all splatted arguments?
ming has quit [Remote host closed the connection]
<FromGitter> <Blacksmoke16> isnt that what you're doing now? via the `.each`?
<FromGitter> <> It doesn't compile
<FromGitter> <HertzDevil> it's doable
<FromGitter> <HertzDevil> ~~if only we had structural pattern matching~~
<FromGitter> <> ```code paste, see link``` []
<FromGitter> <HertzDevil> in that proposal i did many months ago it would look like ⏎ ⏎ ```code paste, see link``` []
<FromGitter> <> I'm confused. I am getting a syntax error before that at `#each`.
<FromGitter> <HertzDevil> you cannot unpack `NamedTuple`s with that `(axis, angle)`
<FromGitter> <HertzDevil> less elegant, of course, is this: ⏎ ⏎ ```code paste, see link``` []
<FromGitter> <> I tried to integrate the more elegant way into that method and I still get an error at `#each`
<FromGitter> <> like said above, you can't unpack that with `(axis, angle)`
<FromGitter> <> make sure you're sure what data structure you're trying to iterate there
<FromGitter> <> Right, I am using the version
Nik- has quit [Quit: My Mac Mini has gone to sleep. ZZZzzz…]
<FromGitter> <> that one doesn't look inelegant to me 🤷
<FromGitter> <> @HertzDevil: Ah I made a small mistake. I got it working now. Thanks for the suggestion!
<FromGitter> <> I'm a bit confused why I have to call it with parentheses. What is this parse error? ⏎ ⏎ ```code paste, see link``` []
<FromGitter> <HertzDevil> it's parsed as a block, the call requires parentheses around arguments in this case
<FromGitter> <> Ah
HumanG33k has joined #crystal-lang
<FromGitter> <> Wonder how acceptable this printed rep is:
<FromGitter> <Blacksmoke16> looks fine
<FromGitter> <> For now, until i get annoyed at variable-length numbers throwing the columns unreadable
<FromGitter> <> Really don't feel like preprocessing all string representations of the floats to see how many characters there are to see how much extra whitespace to pad each one right now :)
<FromGitter> <Blacksmoke16> maybe look into using,separator='.',delimiter=',',decimal_places:Int?=nil,*,group:Int=3,only_significant:Bool=false):Nil-instance-method
<FromGitter> <> @Blacksmoke16: I'm not sure how that will help
<FromGitter> <Blacksmoke16> I guess my thinking was it could be used to make each number the same length
<FromGitter> <Blacksmoke16> But guess not exactly as you can't do left padding or something
<FromGitter> <> What's a good way to create a string of N identical characters?
<FromGitter> <Blacksmoke16> "f" * 10
<FromGitter> <> Thanks. Horrible, but
<FromGitter> <> Is there anything builtin that can partition an array of values into equal parts? except the last part can be shorter obviously
<FromGitter> <Blacksmoke16>,filled_up_with:U=nil,reuse=false,&)forallU-instance-method
ur5us has joined #crystal-lang
<FromGitter> <> Thanks. I guess today turned into how to over-engineer debug printouts
<FromGitter> <Blacksmoke16> :S
<FromGitter> <Blacksmoke16> nice one
<FromGitter> <> haha, what is that emoji?
<FromGitter> <Blacksmoke16> technically it means "confused" but i just like how it looks for contexts like this
<FromGitter> <> I know the code isn't great if that's what you mean. It was my quick prototype. If I wanted to waste a couple months I'd write a library for general-purpose rendering of tabular data.
<FromGitter> <Blacksmoke16> hey if it works it works
<FromGitter> <Blacksmoke16> always be improved later
<FromGitter> <> I just want to not have to squint when I'm debugging why something looks the way it does on frame N when i print out the matrix
<FromGitter> <Blacksmoke16> for sure, deff a good usability feature
<FromGitter> <> I could go farther and not truncate the decimal to 6 places, and track maxes on each side of the decimal to figure out how to align them all, but i think that's getting carried away. speaking of, time for a break. thanks for the help.
<FromGitter> <Blacksmoke16> Np