Skip to content

pr1001/caseclass.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 

Repository files navigation

cassclass.js is an attempt to duplicate the functionality of Scala's case classes in Javascript. This is a work in progress and so far only the class construction works:

Create a case class based upon a name and property list like so:
	CaseClass.create("Person", ["name", "age"]);

Instances of the case class can be created like so:
	var obama = CaseClass.Person("Barack Obama", 47);
	var mccain = CaseClass.Person("John McCain", 72);
	var obama2 = CaseClass.Person("Barack Obama", 47);
	
Note that the 'new' keyword is not needed, just like with Scala's case classes.

The class instance properties are easily accessible:
  obama.name // -> "Barack Obama"
  mccain.age // -> 72

The case class instances can be compared using the equals method:
	obama.equals(mccain); // -> false
	obama.equals(obama2); // -> true

Case classes can be matched against each other like so:
	obama.match(
		{
			caseTest: mccain,
			caseFunction: function() { return 1; }
		},
		{
			caseTest: obama2,
			caseFunction: function() { return 2; }
		},
	); // -> 2

Case tests in the form of comma-seperated strings can be used to extract values while still matching against the case class instance's properties:
  obama.match(
    {
      caseTest: "name, 72",
      caseFunction: function(name) { return name + " is 72 years old."; }
    }
  ) // -> no match
  
  mccain.match(
    {
      caseTest: "name, 72",
      caseFunction: function(name) { return name + " is 72 years old."; }
    }
  ) // -> "John McCain is 72 years old."

  obama.match(
    {
      caseTest: "'Barack Obama', age",
      caseFunction: function(age) { return "Barack Obama is " + age + " years old."; }
    }
  ) // -> "Barack Obama is 47 years old."

Case tests in a matching operation can be a mixture of case class instances and string-based tests:
  obama.match(
    {
      caseTest: "name, 72",
      caseFunction: function(name) { return name + " is 72 years old."; }
    },
    {
      caseTest: obama2,
      caseFunction: function() { return "var obama is the same as var obama2"; }
    }
  ) // -> "var obama is the same as var obama2"
    
Case functions that respond to extracting case tests must currently take parameters in the exact same order:
  obama.match(
    {
      caseTest: "name, age",
      caseFunction: function(age, name) { return age + " years ago " + name + " was born."; }
    }
  ) // -> "Barack Obama years ago 47 was born."

Case functions that respond to extracting case tests will receive as many arguments as the case test extracts values:
  mccain.match(
    {
      caseTest: "name, 72",
      caseFunction: function(name, age) { return name + " is " + age + " years old."; }
    }
  ) // -> "John McCain is undefined years old."
  
The case test can specify the case class to match against. When not specified, the case class of the matching object is assumed:
  obama.match(
    {
      caseTest: "Person(name, age)",
      caseFunction: function(name, age) { return name + " is " + age + " year old." }
    }
  ) // -> "Barack Obama is 47 years old."

  obama.match(
    {
      caseTest: "Politician(name, age)",
      caseFunction: function(name, age) { return name + " is " + age + " year old." }
    }
  ) // -> no match
  
You may also just check the case class, in which case nothing will be passed to the function. Parenthesis are required:
  obama.match(
    {
      caseTest: "Person()",
      caseFunction: function() { return true }
    }
  ) // -> true
  
  obama.match(
    {
      caseTest: "Person",
      caseFunction: function() { return true }
    }
  ) // -> Error: More parameters passed than there are properties in the case class
  
You can pass the case class directly:
  obama.match(
    {
      caseTest: CaseClass.Person,
      caseFunction: function() { return true }
    }
  ) // -> true
  
By default case classes are not added to the global ('window') namespace. If you would like them to be added, simply set the flag to true. You may still use the name-spaced form. For example:
  CaseClass.globals = true;
  CaseClass.create("Person", ["name", "age"]);
  var obama = Person("Barack Obama", 47);
  var obama2 = CaseClass.Person("Barack Obama", 47);
  obama.match(
    {
      caseTest: obama2,
      caseFunction: function() { return true; }
    }
  ) // -> true
  
There is limited support for extractors when matching against other case class instances. If any extractors hints are found, global variables for _all_ the case class's properties are created _if_ the variables do not already exist. You must pass an undefined variable to the caseTest instance to indicate you want to extract a value rather than compare it. Because of this limitation, this extractor functionality is only useful if you need to match against an existing object when extracting unknown values and/or if you love/need the magic of closures in your caseFunction. Otherwise, see above for string-based case tests, which have better extractors:
  delete name;
  delete age;
  var undef;
  obama.match(
    {
      caseTest: CaseClass.Person(undef, 47),
      caseFunction: function() { return "Did you know " + name + " is " + age + " years old?" }
    }
  ) // -> Did you know Barack Obama is 47 years old?
  mccain.match(
    {
      caseTest: CaseClass.Person(undef, undef),
      caseFunction: function() { return "Did you know " + name + " is " + age + " years old?" }
    }
  ) // -> Did you know John McCain is 72 years old?
  obama2.match(
    {
      caseTest: CaseClass.Person("Barack Obama", 47),
      caseFunction: function() { return "Did you know " + name + " is " + age + " years old?" }
    }
  ) // -> ReferenceError: age is not defined [NOTE: There is no error for name because window.name and document.name always exist.]
While this is pretty cool that if works as well as it does given the limitations of Javascript, I'm not wild about this and am just inclined to start passing all arguments to the caseFunction when the caseTest is a case class instance, just like if it's a string.

About

cassclass.js is an attempt to duplicate the functionality of Scala's case classes in Javascript.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published