Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

coffeescript and enum values

I was playing around with the concept of enums / constants in coffeescript ( http://coffeescript.org/ ) and came up with the following code below which seems OK. How can I enhance this to be even better for something where an enum would fit? google searches for this have not yet revealed satisfaction.

class SomeService

  @SomeEnumValue : 400
  @SomeOtherValue : 402

  someFunc: ->
    SomeService.SomeEnumValue 

ok = new SomeService()
alert ok.someFunc()

if (ok.someFunc() == SomeService.SomeEnumValue) then alert ' some enum value'
like image 670
finneycanhelp Avatar asked Feb 20 '12 23:02

finneycanhelp


People also ask

What is enum variable?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.

Can I use enum in JavaScript?

Enums are not supported in JavaScript natively. We can however create Enums using Object. freeze by creating objects containing all the enumerable properties and then freezing the object so that no new enum can be added to it.

Should enums be capitalized?

Enums are a type and the enum name should start with a capital. Enum members are constants and their text should be all-uppercase.

What is enum in JavaScript example?

Enums are types that contain a limited number of fixed values, as opposed to types like Number or String which can have a wide range of values.


6 Answers

I know I'm late to the party, but for posterity I offer up a "coffeethonic" solution (in the spirit of less-typing):

[ a, b, c ] = [1..3]
like image 107
Max Avatar answered Oct 13 '22 08:10

Max


The whole concept of enum is just useless in dynamic languages as is tuple, typed list, map and lots of other stuff, and Javascript (Coffeescript) is dynamic. While working with dynamic language you just have to forget about type checking and use the existing more general constructs to solve your problem. Use arrays instead of lists and tuples, use objects instead of maps and enums and just trust the type of value passed to the function, but heavily unit-test your code. For better or worse (for worse IMO) that's just how a work is done here.

In your case I would recommend just storing your values in a singleton object, like so:

HTTPStatusCodes = 
  ok : 200
  badRequest : 400
  unauthorized : 401

and accessing it like so:

class SomeService
  okCode: ->
    HTTPStatusCodes.ok
  failureCodes: ->
    code for key, code of HTTPStatusCodes when code >= 400
like image 22
Nikita Volkov Avatar answered Oct 13 '22 07:10

Nikita Volkov


I strongly disagree with the statement that Enums are useless due to the dynamic nature of Javascript or the Enums are more less glorified hashes.

To quote Wikipedia: "A variable that has been declared as having an enumerated type can be assigned any of the enumerators as a value." And only these enumerators are possible as values.

Coffeescript can easily and syntactically pleasing emulate an Enum. Including error handling on invalid enumeration values (albeit only at run time)

I have created an example that is mostly functional in nature and uses anonymous callback functions as a means of assignment - basically substituting the assignment operator "=" for Coffeescripts function operator "->". It makes the most syntactically dense code in my book. However a more class based approach is certainly possible.

#define enumeration
httpcodes = Enum 
    ok: 200
    badRequest: 400
    unauthorized: 401
    server_error: 500

#set enum variables with some default state
chrome = httpcodes -> @server_error 
firefox = httpcodes -> @server_error
safari = httpcodes -> @server_error

console.log "httpcodes.ok:" + httpcodes.ok

#change enum value
chrome -> @ok
firefox -> @badRequest
safari -> @unauthorized

console.log "chrome:" + chrome ->
console.log "firefox:" + firefox ->
console.log "safari:" + safari ->

console.log "(chrome ->) == httpcodes.ok:" + ((chrome ->) == httpcodes.ok)

#set an invalid value
try
    safari -> 999
catch err
    console.log err 
    console.log "safari:" + safari ->

And here is the code to create an Enum (you need to put this on top of the code if you want to run it. Just wanted to show the usage code before the implementation code

Enum = (enumeration)->
    check = (value)->
        newval = null
        for key, val of enumeration
            if val == value
                newval = value
                break
        if !newval
            throw "Invalid Enum Value: #{value}"

     result = (init)->
         state = init.call(enumeration)
         check state
         (callback)->
              value = callback.call(enumeration)
              if value == null or value == undefined
                  return state
              else
                  check value
                  state = value

      for key, value of enumeration
          result[key] = value 

      result

Obviously It would be much nicer if Coffeescript would have syntactic macros. So we could write

Enum httpcodes
    ok: 200
    badrequest: 400

and

chrome = httpcodes 'ok
#or
chrome := 'ok
like image 37
robkuz Avatar answered Oct 13 '22 07:10

robkuz


Colors = Object.freeze({
  RED: 'red'
  GREEN: 'green'
  BLUE: 'blue'
})
console.log Colors.RED
# red

Values are constants (you can't change them):

Colors.RED = 'black'
console.log Colors.RED
# red
like image 34
Evmorov Avatar answered Oct 13 '22 08:10

Evmorov


I started the day wondering about enums in coffeescript and ended it with a solution I published on github (available in npm, bower, meteor too). I tried to develop java-like enums, but even more flexible given the mix between prototype inheritance and classical inheritance coffeescript relies on.

Here is how it would fit your code :

class SomeService
  someFunc: -> SomeService.SomeEnumValue
  #A cool hack, but it must be the last class statement. 
  #Your class will now inherit this enumeration's properties. 
  #If you find this too hacky, you can always have a public static 
  #states class property instead.
  @__proto__:new Enumeration('SomeService',{
          SomeEnumValue :400
          SomeOtherValue:402
      })

ok = new SomeService()

alert ok.someFunc().id() #shows 400

if (ok.someFunc() is SomeService.SomeEnumValue) then alert ' some enum value'

But what's cool in this implementation, is that your enum can have specific fields, and inherit from a prototype (3d constructor argument) though uniqueness is guaranteed. That allows you to refactor your code and move some logic inside those function. Let's now ask this enum value to tell us something when he needs to, by defining a tell function.

class SomeService
  someFunc: -> SomeService.SomeEnumValue
  #A cool hack, but it must be the last class statement. 
  #Your class will now inherit this enumeration's properties. 
  #If you find this too hacky, you can always have a public static 
  #states class property instead.
  @__proto__:new Enumeration('SomeService',
                SomeEnumValue : { _id:400, text: ' some enum value' }
                SomeOtherValue: { _id:402, text: null } 
        , tell:->if @text? then alert @text)

ok = new SomeService()

alert ok.someFunc().id() #shows 400

ok.someFunc().tell()

Hope this helps someone, you can check the github address to have a look at the implementation and some more detailed documentation I wrote.

like image 40
Jules Sam. Randolph Avatar answered Oct 13 '22 06:10

Jules Sam. Randolph


For people looking for a simpler solution, that doesn't need to be fail-safe, where the values of the keys don't matter:

Priority = {
  "LOW"
  "HIGH"
}

priority = Priority.HIGH
like image 44
Felipe Müller Avatar answered Oct 13 '22 08:10

Felipe Müller