jashkenas / coffeescript

Unfancy JavaScript
https://coffeescript.org/
MIT License
16.5k stars 1.99k forks source link

seems #1132

Closed dvv closed 13 years ago

dvv commented 13 years ago

Hi!

Having read http://bonsaiden.github.com/JavaScript-Garden/#typeof realized the cause of why I ago lost a day finding a bug in my node.js code -- could not imagine that typeof /a/ is 'function'.

The proposal is to introduce in coffee the special operator seems which should return the string denoting the type of operand in confident way. The realization could be borrowed from underscore.js.

E.g. 2 seems 'number' is (new Number(2)) seems 'number' is true.

What do you think?

Best regards, --Vladimir

michaelficarra commented 13 years ago

This seems more appropriate for a a library. CS usually tries to keep this kind of fluff outside of the language unless it's a really common pattern. This doesn't seem like anything I would ever make use of, and I know it's something I never have.

edit: I'm going to mark this as a wontfix, since I'm sure jashkenas agrees, but I'll leave it open so that it at least passes under his nose. And any other feedback in support of or against this issue would help.

dvv commented 13 years ago

So how do you test the type of a value?

michaelficarra commented 13 years ago

Type-checking isn't really a common pattern in JS because of its loose typing paradigm. You should just be duck-typing. The only time I personally use typeof is for undeclared reference testing, but CS solves that with its existence (?) and safe property access (?./?[]) operators. What's the specific problem you're trying to solve?

dvv commented 13 years ago

I might have used the wrong wording to explain my point, but I did exactly meant seems is for duck-typing. I want to completely avoid relying on typeof (and may be instanceof) in my code and would recommend to do so the others.

But type (duck- or not) checking is certainly of value. I've much code which deals with values which can be string/array/function, and the code behavior is different in these cases. E.g. if function -- call it and use the return value, if string -- reference an object property, if array -- drill down into object, steps beings items of the array.

I do know CS is trying to be JS engine neutral, and pure -- but the suggested and recommended way for people to start using duck-typing is hardened by the lack of means in the language. The dangerous stuff should be hidden and hard to call, while the recommended way should be clear and easy to use. I won't suggest to replace typeof since there might be code depending on it, but to say the truth it should be replaced, imho. Or, a new type tester.

I also find it quite natural for literate programming to associate seems to duck-typing test, otherwise I'd have suggested introducing ducktypeof :)

michaelficarra commented 13 years ago

Eh, it seems you have a different idea of "duck-typing". I didn't mean trying to determine some "type" (whether it be the internal [[Class]] or whatever) of an object by what properties it has, but writing your program to only depend on an object that has certain properties. Do you understand now what I meant? It would probably help if you posted a gist containing your problematic code.

dvv commented 13 years ago

I understand your point, but I'd like to have robust "give-me-the-type" tool in the language. typeof and instanceof are not such.

We don't have means to do for (var i in array) {}. I guess this restriction has rationale to not allow doing bad/deprecated things. We do have for own k, v of hash to ease robust iteration over own props. These are signs of that CS tries to teach the best practices, ain't it? typeof and instanceof are not robust. By kicking them CS could promote recommended way of type checking.

This issue is not limited by a particular problem, this is an attempt to make CS promote good code style, the latter being recommended by JS coders themselves.

As an example I'll soon be spawning a repo here which has many to do with typing.

satyr commented 13 years ago

What compilation are you expecting?

dvv commented 13 years ago

I'd expect typeof overloaded behind the scene, to return the right string. So CS typeof X compiles down to __typeof(X) defined once for the source file just like for __hasOwnProperty. __typeof can be a simple when/then, reusing underscore _.isXXX() logic which seems pretty useful yet non-bloaty

So: t = typeof /node.js/ # t = __typeof(/node.js/); console.log 'well done CS' if t is 'object'

The plain JS' typeof can still be accessed via backticks.

And may be seems keyword to put syntactic sugar: console.log 'good' if 2 seems 'number' # if _.isNumber 2 console.log 'better' if (new Number(2)) seems 'number' console.log 'cool' if (new RegExp('v8')) seems 'object'

jashkenas commented 13 years ago

I'm afraid that Michael has this one down cold. This sort of operation isn't the kind of thing that gets added to CoffeeScript ... and even elsewhere in JavaScript it's not a great idea. The simple fact is that JavaScript has a very poor set of types, and there's very little good that can come out of trying to name them with strings -- the real useful typechecking is saying "is this object an arguments object or a real array" ... "is this object null or undefined" -- that sort of thing.

Closing the ticket.

michaelficarra commented 13 years ago

Also, I remembered that I sometimes use

typeof callback == "function"
for checking if I should call a callback. But that's the extent of the usefulness of typeof.

dvv commented 13 years ago

michaelficarra: consider trying your code in Chrome/node.js to test if typeof /i-am-function-you-know/ == 'function'.

jashkenas: "is this object an arguments object or a real array" == _.typeof(obj) in ['object', 'array'] == _.typeof = (obj) -> return 'object' if _.isObject(obj); return 'array' if _.isArray(obj); ... and so on all _.isXXX ...

Just don't see why so dense objection.

michaelficarra commented 13 years ago

@dvv: Do I care? It's callable, which is exactly what I was looking for. I wasn't looking for an instance of Function. You're still just missing this whole duck-typing thing...

dvv commented 13 years ago

You don't care of consistent behavior across the engines? Why?

michaelficarra commented 13 years ago

Ugh, I do. I care that the value that I'm calling (using ()) is callable. RegExps are callable in some implementations, and they will produce "function", consistent with my expectations.

dvv commented 13 years ago

Frankly, how do you yourself check that a value is a regexp, or a number, or a date? Mind to share your pattern of doing this with coffee-script?

michaelficarra commented 13 years ago

Maybe this is a better way to explain it. Javascript doesn't have those things. It has objects, that's all. Some of those objects have a constructor property of RegExp. Some of those objects have an internal [[Class]] property of Date. Some of those objects produce "undefined" when the typeof operator is applied to them. Some of those objects produce true when compared to the empty string with ==. Some of those objects have their own hasOwnProperty property. You need to test for the feature that you want to use. It's always dependent on the situation. There are no real "types". Hopefully you will get it this time.

edit: pedantics: please don't be pedantic about this post. I'm trying to get an idea across.

dvv commented 13 years ago

I see. I understand that in JS any object (except null?) can have traits of any "type-as-we-know-it-in-other-languages". An array being given a .match property can pretend to be regexp etc. That is ok.

Now I see classes implemented in coffee-script -- this is the helper to deal with common pattern in JS, but admit JS has no classes (just like it has no types either), right? So imho classes in coffee-script ease the use of common pattern (classic inheritance) which people got accustomed to. And that is ok again.

Now despite JS has no types there are tasks to analyse of what flavor the object you are given. It really doesn't matter on what basis this flavor is determined -- duck-typing or not -- just means needed to classify what is object capable to do.

Now the chances high that people will you underscore.js to perform this classification. This library has close to complete set of duck-type testers _.isXXX(). This is ok unless you already work in ES5 environment which has native implementations of most features for iterables and functions, which older engines miss. But in turn ES5 miss duck-type testers, and force people to reinvent their own. So those who rely on plain typeof risk to write wrong code.

What I'm suggesting is to port _.isXXX routines to coffee-script, so people could properly use duck-typing OOTB. If in coffee-script obj typeof XXX compiled behind the scene to (_.isXXX(obj)), and _.isXXX were internally defined (like __hasProp, __slice et al.), we'd get consistent syntax plus robust duck-typing w/o any loss in readability.

Have sense?