JSObject Wrapper Types

jbracker edited this page Apr 8, 2013 · 14 revisions

It is sometimes useful to introduce wrapper types (e.g. JSDate, JSCanvas) around JSObject to gain a bit more type safty. When implementing these don't forget to provide the following instances:

  • Sunroof - All these wrapper types should be sunroof values (otherwise they are useless).
  • BooleanOf - Without this binding using the type inside if-then-else is impossible.
  • IfB - Without ifB will not be available for the wrapper.
  • EqB - This should be implemented with reference equality to be consistent with Javascript. This also means it is always possible to implement this class.

Template Haskell: For simple wrappers, like the one given in the example below, you can also use the module Language.Sunroof.TH to derive all instances except the EqB instance, through template Haskell.


Here an example implemention for the not existing type JSWrapper. It is advised to provide the comment for EqB in the example to ensure that readers of the documentation know what is going on. The Show instance given is convenient for debugging but not necessary.

newtype JSWrapper = JSWrapper JSObject

-- | Show the Javascript.
instance Show JSWrapper where
  show (JSWrapper o) = show o

-- | First-class values in Javascript.
instance Sunroof JSWrapper where
  box = JSWrapper . box
  unbox (JSWrapper o) = unbox o

-- | Associated boolean is 'JSBool'.
type instance BooleanOf JSWrapper = JSBool

-- | Can be returned in branches.
instance IfB JSWrapper where
  ifB = jsIfB

-- | Reference equality, not value equality.
instance EqB JSWrapper where
  (JSWrapper a) ==* (JSWrapper b) = a ==* b

This requires the following imports and language extensions:

{-# LANGUAGE TypeFamilies #-}

import Data.Boolean ( BooleanOf, IfB(..), EqB(..) )
import Language.Sunroof.Classes ( Sunroof(..) )
import Language.Sunroof.JS.Bool ( JSBool, jsIfB )
import Language.Sunroof.JS.Object ( JSObject )