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'
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.
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.
Enums are a type and the enum name should start with a capital. Enum members are constants and their text should be all-uppercase.
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.
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]
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
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
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
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With