New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Operator for comparison with type coercion #1693

Closed
wallin opened this Issue Sep 12, 2011 · 10 comments

Comments

Projects
None yet
7 participants
@wallin

wallin commented Sep 12, 2011

I'm quite new to coffescript and maybe this has been up for discussion before, but I couldn't find anything related.

Now, in some rare cases, I find my self wanting to use the double equal (==) operator in javascript, especially when comparing numbers (eg. when sent as strings in some response by some server).

I know that you can solve the number comparision problem by using parseInt because you know what to expect, but what are your thoughts of having a special operator, like for example ~=, that maps to the == operator in Javascript?
At least then it's up to the user to make an active decision to enforce type coercion. But then again, maybe it's not right to encourage usage of something that is somewhat non-deterministic.

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas Sep 12, 2011

Owner

This is a duplicate of at least a couple previous tickets, although my github search skills are failing me at the moment.

We don't want to have == in CoffeeScript because it's coercive, intransitive, and entirely unnecessary.

In the one place where it's truly useful in JS, you can use the existential operator instead:

if object.property?
  action()

... checks if property is null or undefined, via ==.

If you want to compare numbers as strings, convert them to strings ... and if you want to compare strings as numbers, parse them as numbers.

For some broken == fun:

8 == '08'
> true

8 == '0x8'
> true

8 == '0xa8'
> false
Owner

jashkenas commented Sep 12, 2011

This is a duplicate of at least a couple previous tickets, although my github search skills are failing me at the moment.

We don't want to have == in CoffeeScript because it's coercive, intransitive, and entirely unnecessary.

In the one place where it's truly useful in JS, you can use the existential operator instead:

if object.property?
  action()

... checks if property is null or undefined, via ==.

If you want to compare numbers as strings, convert them to strings ... and if you want to compare strings as numbers, parse them as numbers.

For some broken == fun:

8 == '08'
> true

8 == '0x8'
> true

8 == '0xa8'
> false

@jashkenas jashkenas closed this Sep 12, 2011

@wallin

This comment has been minimized.

Show comment
Hide comment
@wallin

wallin Sep 12, 2011

Thanks for a good answer, I figured that this question ought to be a dupe =)

I understand your point from a readability perspective: by doing the casting yourself, you tell the world that you think you know what you're doing. But from a number parsing perspective I don't see why 8 == '0x8' or eg. 16 == '0x10' evaluating to true is wrong or broken. It's basically the same as 16 === parseInt('0x10', 16). But that's a different discussion. I guess that all a ~=-operator would do in the number parsing case is to save you some typing.

wallin commented Sep 12, 2011

Thanks for a good answer, I figured that this question ought to be a dupe =)

I understand your point from a readability perspective: by doing the casting yourself, you tell the world that you think you know what you're doing. But from a number parsing perspective I don't see why 8 == '0x8' or eg. 16 == '0x10' evaluating to true is wrong or broken. It's basically the same as 16 === parseInt('0x10', 16). But that's a different discussion. I guess that all a ~=-operator would do in the number parsing case is to save you some typing.

@whatcould

This comment has been minimized.

Show comment
Hide comment
@whatcould

whatcould Feb 13, 2012

Jeremy, this is one of the things where Coffeescript adds annoying behavior to JS instead of taking it away. 8 == '8' is the common case, the principle of least surprise; what Coffeescript does with replacing == with === is made developers exchange this:

  • I have to remember to use === some of the time, when I don't want coercion

for this:

  • I have to remember to use parseInt('8') == 8 A LOT of the time

Wallin's suggestion of an ~= comparison would at least cut down on all the extraneous parseInt()

whatcould commented Feb 13, 2012

Jeremy, this is one of the things where Coffeescript adds annoying behavior to JS instead of taking it away. 8 == '8' is the common case, the principle of least surprise; what Coffeescript does with replacing == with === is made developers exchange this:

  • I have to remember to use === some of the time, when I don't want coercion

for this:

  • I have to remember to use parseInt('8') == 8 A LOT of the time

Wallin's suggestion of an ~= comparison would at least cut down on all the extraneous parseInt()

@jashkenas

This comment has been minimized.

Show comment
Hide comment
@jashkenas

jashkenas Feb 13, 2012

Owner

@whatcould: I'm afraid we'll have to disagree about that. 8 == '8' is a huge source of bugs in JavaScript, and CoffeeScript's removal of it is a significant feature. Yes, if you're taking strings out of the DOM, you'll have to convert them into real integers before treating them as such, but you'd have to do that anyway... Otherwise:

var result = 5;

var num = $("input").val();

if (num == 8) {
  result = num + result;
}

... and your result number is now the string "85". Whoops.

Owner

jashkenas commented Feb 13, 2012

@whatcould: I'm afraid we'll have to disagree about that. 8 == '8' is a huge source of bugs in JavaScript, and CoffeeScript's removal of it is a significant feature. Yes, if you're taking strings out of the DOM, you'll have to convert them into real integers before treating them as such, but you'd have to do that anyway... Otherwise:

var result = 5;

var num = $("input").val();

if (num == 8) {
  result = num + result;
}

... and your result number is now the string "85". Whoops.

@erisdev

This comment has been minimized.

Show comment
Hide comment
@erisdev

erisdev Feb 13, 2012

@jashkenas Don't forget the totally wack 0x10 == '0x10' && 010 != '010' // => true.

erisdev commented Feb 13, 2012

@jashkenas Don't forget the totally wack 0x10 == '0x10' && 010 != '010' // => true.

@satyr

This comment has been minimized.

Show comment
Hide comment
@satyr

satyr Feb 13, 2012

Collaborator

Don't forget we do still have type-coercing operators:

$ coffee -e 'console.log "0xC" < 15 <= "0xF"'
true
Collaborator

satyr commented Feb 13, 2012

Don't forget we do still have type-coercing operators:

$ coffee -e 'console.log "0xC" < 15 <= "0xF"'
true
@whatcould

This comment has been minimized.

Show comment
Hide comment
@whatcould

whatcould Feb 18, 2012

Ok, I do see how it causes bugs; maybe it's just getting used to the different paradigm.

Doing some googling I was reminded that: + will coerce integers, eg: +$('input').val() == 8. Which is a lot cleaner than parseInt, so it solves my aesthetic annoyance!

whatcould commented Feb 18, 2012

Ok, I do see how it causes bugs; maybe it's just getting used to the different paradigm.

Doing some googling I was reminded that: + will coerce integers, eg: +$('input').val() == 8. Which is a lot cleaner than parseInt, so it solves my aesthetic annoyance!

@ELLIOTTCABLE

This comment has been minimized.

Show comment
Hide comment
@ELLIOTTCABLE

ELLIOTTCABLE May 26, 2013

Contributor

Just throwing my voice in here:

While I understand the reasons for removing it completely, there's another use-case that nobody seems to consider: boxed-types. Which definitely have their own wide-spread uses in various corners of JavaScript and not-so-obscure approaches to problems.

Without any coercive operator, it's impossible for me to take both boxed-natives and unboxed-natives to the same function without an unnaturally quantity of boilerplate for every argument that may be boxed:

arg = arg.valueOf() if arg instanceof String

… and then that becomes even more ugly, complex, and fragile, if I'm accepting multiple types of primitive for a given argument (say, a string or an integer.)

Not saying that this alone is enough reason to bring a =~ operator to CoffeeScript; but nonetheless, it's something that must be considered when discussing the issue.

Contributor

ELLIOTTCABLE commented May 26, 2013

Just throwing my voice in here:

While I understand the reasons for removing it completely, there's another use-case that nobody seems to consider: boxed-types. Which definitely have their own wide-spread uses in various corners of JavaScript and not-so-obscure approaches to problems.

Without any coercive operator, it's impossible for me to take both boxed-natives and unboxed-natives to the same function without an unnaturally quantity of boilerplate for every argument that may be boxed:

arg = arg.valueOf() if arg instanceof String

… and then that becomes even more ugly, complex, and fragile, if I'm accepting multiple types of primitive for a given argument (say, a string or an integer.)

Not saying that this alone is enough reason to bring a =~ operator to CoffeeScript; but nonetheless, it's something that must be considered when discussing the issue.

@SimplGy

This comment has been minimized.

Show comment
Hide comment
@SimplGy

SimplGy Aug 29, 2014

I know the decision's already been made here, but I love an opt-in solution for this that allows us to use coercion when we intend for it to happen. I see valid use cases for this outside of null == undefined. Manual coercion works but it's ungainly sometimes.

Maybe if an ugly and rough-sounding enough work was picked, the intent would be clear and bugs would be avoided. I thought about it overnight and landed on ish. It's beautiful because it's one char away and sounds like what it is.

# default
input = val: "42"        # mocking an html text input
input.val is  42         # false
input.val is String 42   # true
input.val ish 42         # true

It's not ungainly to convert a string to a number (+"42"), but it's more annoying to convert a number to a string. (String 42 or '' + 42).

SimplGy commented Aug 29, 2014

I know the decision's already been made here, but I love an opt-in solution for this that allows us to use coercion when we intend for it to happen. I see valid use cases for this outside of null == undefined. Manual coercion works but it's ungainly sometimes.

Maybe if an ugly and rough-sounding enough work was picked, the intent would be clear and bugs would be avoided. I thought about it overnight and landed on ish. It's beautiful because it's one char away and sounds like what it is.

# default
input = val: "42"        # mocking an html text input
input.val is  42         # false
input.val is String 42   # true
input.val ish 42         # true

It's not ungainly to convert a string to a number (+"42"), but it's more annoying to convert a number to a string. (String 42 or '' + 42).

@ELLIOTTCABLE

This comment has been minimized.

Show comment
Hide comment
@ELLIOTTCABLE

ELLIOTTCABLE Sep 23, 2014

Contributor

I like @SimpleAsCouldBe's suggestion quite a lot, for whatever that's worth. 👍

Contributor

ELLIOTTCABLE commented Sep 23, 2014

I like @SimpleAsCouldBe's suggestion quite a lot, for whatever that's worth. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment