mna / agora

a dynamically typed, garbage collected, embeddable programming language built with Go
https://github.com/mna/agora/wiki
BSD 3-Clause "New" or "Revised" License
324 stars 27 forks source link

Make "" and 0 truthy #24

Closed luther9 closed 10 years ago

luther9 commented 10 years ago

In Lua and Ruby, the only falsy values are nil and false. This makes it very convenient to check if a value is defined without worrying about what types the value may be. (It's usually easy to know if a value may be boolean.) If strings and numbers are allowed to be false, then I have to worry about how I will treat those special falsy values in every if statement. That's a lot of extra mental load, and it would be worse than if the interpreter to threw an error for non-boolean if expressions. Historically, when other languages allow "" and 0 to be false, it's because the language did not start out with a native boolean type, and they want backward compatibility. I hope you'll reconsider this.

mna commented 10 years ago

And Python and javascript, among others, have those falsy values. I don't see how it is easy to know if a value is a boolean, but hard if it is a string or number. Basically, if you check for if obj.Field { }, it's because in that case a significant value would be only non falsy. Otherwise you would check with != nil.

That's a very small "price" to pay, and you get constructs such as var := x || "default" that can be useful for default values.

as stated in the docs, the goal is to provide a looser language, not to make strictly a typeless Go (which could be interesting in its own right, but it just isn't agora).

BenLubar commented 10 years ago

+1 for keeping "" and 0 'falsy'

As a programmer, I expect languages to work similarly. There are two ways I've seen if (string) and if (number) handled: treating the "zero value" as false, or having it be a compile-time error. Agora can't make it a compile-time error because it doesn't know what type of value a variable holds at compile time.

luther9 commented 10 years ago

"And Python and javascript, among others, have those falsy values." Yes, and it's a PITA to work with.

"I don't see how it is easy to know if a value is a boolean, but hard if it is a string or number." For one thing, you have twice as many data types that can be potentially false, which means twice as many special-case values that I have to consider every time I write or try to understand an if statement. I could write more explicit checks to avoid thinking about it, but then I don't get any benefit from the extra falsy values, and that still doesn't help me when reading other people's code. Secondly, bools don't usually make sense in the same context as other non-nil types, so we can often treat nil and false as being the same.

"Basically, if you check for if obj.Field { }, it's because in that case a significant value would be only non falsy. Otherwise you would check with != nil." Unset Object fields and unset function parameters both yield nil (as in Lua). So nil checks will be much more common than checks for "significant" values. Why should "" and 0 be considered insignificant? To build that decision into the language seems unnecessarily complex to me. I don't see how that would be helpful to a casual programmer.

"That's a very small "price" to pay, and you get constructs such as var := x || "default" that can be useful for default values." It's much easier to use that construct when there's only two falsy values. I use that idiom all the time in Lua, but I don't think I've ever used it in Python. It's rare that "" and 0 are invalid values that need to be replaced by a default, especially when the caller can more easily pass nil.

Whatever your definition of "loose" is, my experience leaves no doubt in my mind that the Lua way greatly reduces the need for equality checks.

"There are two ways I've seen if (string) and if (number) handled: treating the "zero value" as false, or having it be a compile-time error." That's really only true for staticly typed languages. With dynamic typing, values have to carry their type with them, so they can never really be "zero" in the Go sense (unless they're nil, much like Go's interface{}).

The "zero value" idea works well in C because it works exactly the same way for all data types, and the type of the 'if' expression is staticly known. If a scripting language has too many falsy values, we get a multiplicity that C just doesn't have.

Ok, that was a long post. I hope I didn't repeat my points too much.

mna commented 10 years ago

Hi Luther,

Thanks for expanding on your point of view. I understand that falsy values are a touchy subject, I actually mentioned somewhere that - at least if people noticed the project - this was going to be controversial. I'm not sure I agree that it's a PITA, I have written a lot of JS/node, and it actually allows some useful constructs.

You're right that nil checks will probably be more common, since missing fields are nil. But we have to see this in the context of the programming language, this is not a new Python or Ruby, this is a small companion language to write scripts that will bring dynamic plugins (and things like that) to an otherwise static Go program. Granted, the exact use-cases of agora are unclear at the moment, but I think that programs like reading input from the user, or reading configuration files, and loading dynamic behaviour based on this input may be common.

In this scenario, it is not rare to see an empty string as an invalid input, and using data := "" || "default" may actually be very helpful (replace "" with a variable, that's just to better illustrate the point). So while the nil-as-false will be very useful and still easy to check for existing fields, I believe there's some clear advantage, and not a lot to trade-off, to keep those falsy values in.

And yes, "loose" is vague definition of what I have in mind for the language :) It's a delicate balance to aim for, and the worst part is, even if I nail it for me, it may seem like a total failure for others. So the best I can do is take into account the comments and suggestions I get, and ultimately make my own mind because either way, I won't please everyone, so better to at least please myself!

With that said, expect falsy values to stay at least for the next 2 versions, while I'm still building the features I have on the roadmap. Then we'll all have a better idea of what makes sense and what doesn't, in the context of agora and not from a general PL-design point of view.

Martin