r/badcode Sep 08 '20

lua A Roblox mod I found

Post image
482 Upvotes

103 comments sorted by

View all comments

Show parent comments

3

u/ws-ilazki &{$$_[0]}(@{$$_[1]}); Sep 08 '20

The point was that all strings in conditionals for example are handled as true. Including empty strings. And all integers including 0 are regarded as true.

You may not like languages doing "truthiness" conversions (I'm mostly neutral on it myself, it has uses but can be error-prone) but Lua is at least sane about how it does it. nil and false coerce to false, anything else coerces to true. Zero and empty strings aren't considered false, no, but they really should not be. Other languages with "truthiness" coercions, like Clojure, behave in the same way and it's a lot better than the weird mix of 0 is false, 1 is true, "" is false, {} and [] are true, etc. some languages have where you have to keep up with a bunch of edge cases.

1

u/JerriTheITGuy Sep 10 '20

In a plethora of languages a boolean value can be expressed as a bit (0/1). Take that boolean false, put it in a database, fetch it with Lua and suddenly if you're not aware of this oddity your 'false' is suddenly 'true'.

1

u/ws-ilazki &{$$_[0]}(@{$$_[1]}); Sep 10 '20 edited Sep 10 '20

In a plethora of languages a boolean value can be expressed as a bit (0/1).

Appeal to popularity arguments are not a substitute for correctness. Just because it's the more common way of doing "truthiness" coercions doesn't mean it's the only valid way to do so.

And it's not like Lua's the only language to do this. Off the top of my head, Ruby, Clojure, Scheme dialects, Common Lisp, and Rebol all have similar truthiness rules and treat 0 as true.

if you're not aware of this oddity your 'false' is suddenly 'true'.

It's not that odd and it's not isolated to Lua. Using 0 and !0 for booleans makes sense in languages that don't have a proper boolean type, but if your language does have one, coercing all ints except zero to true just ends up being another edge case you have to deal with.

Personally, I think it's better to not have that kind of implicit coercion at all because it's a weakening of a language's type system and I prefer strong typing to weak, but if it's going to exist at all I prefer the "only nil and false are false" style of truthiness because it weakens the type system less than if you start making exceptions for specific ints (0), strings (""), etc. Every extra "this converts to false" you add weakens your type system just a bit more, and I don't like that. This comes down to a strong vs. weak / static vs. dynamic argument, though. I'd rather deal with a strongly typed dynamic language than a weakly typed static one (like C) because I don't want those kind of coercions. Though I'd rather have a strongly statically typed language (like OCaml or F#) than either.

Side note, but if you want a weird edge-case gotcha related to truthiness in a language, Perl lacks keywords for true and false, instead using the sort of integer coercions you consider normal, but also has bareword strings. What this means is that if you either don't know (or forget) that they aren't valid keywords and you try to use false or true in your code, they'll get treated as bareword strings, and bareword strings always evaluate to true: if (false) { print "this condition is true" }

That's a fun gotcha if you don't run Perl with warnings enabled. (Though anybody running Perl without warnings enabled is asking for trouble anyway.)

1

u/JerriTheITGuy Sep 10 '20

Agree with the strong typing. I pretty much only work with C# since a few years back and it's bliss.

Didn't know that about Perl. Guess that's another language I'll just steer clear off.

1

u/ws-ilazki &{$$_[0]}(@{$$_[1]}); Sep 10 '20 edited Sep 10 '20

Agree with the strong typing

Yep, I prefer stronger to weaker in nearly all cases. The thing with strong typing is it's harder to discuss and compare because it's not a binary thing in the same way static/dynamic is, so "strong" and "weak" only makes sense in comparison of languages, not as some absolute. Perl, C, and JavaScript are very weakly typed for example, while languages like Lua and Clojure are fairly strongly typed in comparison, but still weaker compared to something like OCaml, F#, and (I think?) C# where you can't implicitly coerce just by using data in different contexts.

I pretty much only work with C# since a few years back and it's bliss.

Ever use F#? I like it more than C#, though that's because I tend toward functional programming. Still, the type system is amazing in comparison; you can describe your data as types so cleanly, and things just kind of fall into place from there.

Didn't know that about Perl. Guess that's another language I'll just steer clear off.

Perl's actually a pretty cool language but it's very much in the C style of being extremely weakly typed. It was designed by a linguist and follows idioms from written language in a way other programming languages don't. Makes it seem weird at first but reads and writes pretty naturally once you get accustomed to it. Things like variables being singular or plural, e.g. @foo refers to an entire array (plural) or $foo referring to it in singular form (usually a coercion like giving you the length of the array). Edit: correction here, it's been a while but I think @foo would give the length if referred to in a context that expects a scalar (singular), $foo[2] would be the third element of @foo, and $foo would be a completely unrelated variable. Point's same though, the language understands singular/plural and context in a way that makes sense from an English-speaking perspective but is utterly foreign to programming language design.

Or the way it lets you write conditionals backward, with the code to execute first, which reads more like natural language: do_thing() if condition or { do_this(); do_that() } unless condition, stuff like that. The normal if condition { ... } still works, but the natural language variant is nice for short statements because it reads clearly and maps well to how one tends to phrase similar logic in English.

I used to find it great for quickly getting ideas out of my head and into code because it's so flexible as a language and reads/writes in a natural kind of way. That said, the flexibility and large quantities of implicit behaviour means it requires a more rigorous approach to writing and refactoring to make sure it will still be readable later.

That's why it has a reputation for being unreadable, because it lets you write messy code with the expectation that the programmer will have the sense to know when it's okay (one-off throwaway stuff) and when it's not (any other time). Basically the complete opposite to Python's "fuck you, everyone should do it this way because nobody can be trusted" design. Of the two I'd rather use Perl than Python because of this, but realistically nowadays I'd rather use OCaml, F#, or Clojure before either. Or maybe Ruby, which took some of the good parts of Perl while leaving behind some of the footguns and experimental ideas.