1
0
Fork 0
Classical object-oriented framework for JavaScript [unmaintained] https://gnu.org/software/easejs
 
 
 
 
 
 
Go to file
Mike Gerwitz ac1a0368cf
Preliminary support for traits as mixins
This has turned out to be a very large addition to the project---indeed,
with this release, its comprehensiveness remains elusive, but this is a huge
step in the right direction.

Traits allow for powerful methods of code reuse by defining components that
can be ``mixed into'' classes, almost as if the code were copied and pasted
directly into the class definition. Mixins, as they are so called, carry
with them the type of the trait, just as implementing an interface carries
with it the type of the interface; this means that they integrate into
ease.js' type system such that, given some trait T that mixes into class C
and an instance of C, it will be true that Class.isA( T, inst ).

The trait implementation for GNU ease.js is motivated heavily by Scala's
implementation of mixins using traits. Notable features include:

  1. Traits may be mixed in either prior to or following a class definition;
     this allows coupling traits tightly with a class or allowing them to be
     used in a decorator-style manner prior to instantiation.

  2. By mixing in a trait prior to the class definition, the class may
     override methods of the trait:

       Class( 'Foo' ).use( T ).extend( { /*...*/ } )

     If a trait is mixed in after a class definition, then the trait may
     instead override the functionality of a class:

       Class( 'Foo', { /*...*/ } ).use( T )

  3. Traits are stackable: By using the `abstract override' keyword
     combination, a trait can override the concrete definition of its
     parent, provided that the abstract definition is implemented by the
     trait (e.g. by implementing a common interface). This allows overrides
     to be mixed in any order. For example, consider some class Buffer that
     defines an `add' method, accepting a string. Now consider two traits
     Dup and Upper:

       Buffer.use( Dup ).use( Upper )().add( "foo" )

     This would result in the string "FooFoo" being added to the buffer.
     On the other hand:

       Buffer.use( Reverse ).use( Dup )().add( "foo" )

     would add the string "Foofoo".

  4. A trait may maintain its own private state and API completely disjoint
     from the class that it is mixed into---a class has access only to
     public and protected members of a trait and vice versa. This further
     allows a class and trait to pass messages between one-another without
     having their communications exposed via a public API. A trait may even
     communicate with with other traits mixed into the same class (or its
     parents/children), given the proper overrides.

Traits provide a powerful system of code reuse that solves the multiple
inheritance problems of languages like C++, without introducing the burden
and code duplication concerns of Java's interfaces (note that GNU ease.js
does support interfaces, but not multiple inheritance). However, traits also
run the risk of encouraging overly rich APIs and complicated inheritance
trees that produce a maintenance nightmare: it is important to keep concerns
separated, creating classes (and traits) that do one thing and do it well.
Users should understand the implications of mixing in traits prior to the
class definition, and should understand how decorating an API using mixins
after a class definition tightly couples the trait with all objects derived
from the generated class (as opposed to the flexibility provided by the
composition-based decorator pattern). These issues will be detailed in the
manual once the trait implementation is complete.

The trait implementation is still under development; outstanding tasks are
detailed in `README.traits`. In the meantime, note that the implementation
*is* stable and can be used in the production environment. While
documentation is not yet available in the manual, comprehensive examples and
rationale may be found in the trait test cases.

Happy hacking!
2014-03-15 23:50:21 -04:00
doc Mention of "Traits as mixins" in README.md and manual 2014-03-15 21:16:27 -04:00
lib Deleted unnecessary trait abstract method in favor of auto-abstract flag 2014-03-15 21:16:27 -04:00
test Prohibiting trait getters/setters 2014-03-15 21:16:27 -04:00
tools rmtrail now handles single-line comments following trailing comma 2014-03-07 00:47:28 -05:00
.gitignore Added test/runner to run individual test cases 2014-02-14 00:41:49 -05:00
COPYING Split COPYING into two separate files: COPYING and COPYING.LGPL 2012-06-13 22:27:48 -04:00
Makefile.am Added test/runner to run individual test cases 2014-02-14 00:41:49 -05:00
README [copyright] Copyright update 2014-01-20 22:55:29 -05:00
README.hacking Added beginning of README.hacking 2011-09-02 22:24:16 -04:00
README.md Mention of "Traits as mixins" in README.md and manual 2014-03-15 21:16:27 -04:00
README.todo Removed unit test refactoring mention from README.todo 2014-01-20 22:14:42 -05:00
README.traits README.traits containing remaining TODOs 2014-03-15 22:19:07 -04:00
configure.ac Added test/runner to run individual test cases 2014-02-14 00:41:49 -05:00
index.js Exposing Trait module 2014-03-15 21:16:27 -04:00
package.json.in package.json is now generated by configure script and included in distribution 2013-12-22 01:05:28 -05:00

README.md

GNU ease.js

GNU ease.js is a classical object-oriented framework for Javascript, intended to eliminate boilerplate code and "ease" the transition into JavaScript from other object-oriented languages.

Current support includes:

  • Simple and intuitive class definitions
  • Classical inheritance
  • Abstract classes and methods
  • Interfaces
  • Traits as mixins
  • Visibility (public, protected, and private members)
  • Static and constant members

Documentation

Comprehensive documentation and examples are available on the GNU ease.js website and in its manual.

Bug Reports / Feature Requests

Please direct bug reports and feature requests to bug-easejs@gnu.org or the project page on Savannah.

Why Classical OOP in JavaScript?

GNU ease.js was created (historically) for a number of reasons:

  • To "ease" object-oriented developers into JavaScript by providing a familiar environment.
  • To provide the maintenance and development benefits of classical OOP.
  • To provide features not included in the language, such as proper encapsulation through private/protected members, interfaces, traits, intuitive inheritance, and other conveniences.
  • To encapsulate the hacks commonly used to perform the above tasks.

Many JS purists believe that classical object-oriented programming should be left out of JavaScript and that one should stick strictly to prototypal development. While the two are related (they are both object-oriented), they can be applied to different problem domains in order to achieve results that are more natural or intuitive to developers; GNU ease.js works seamlessly with existing prototypes, allowing the developer to choose whether or not they want to use "classes".

License

ease.js is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

N.B.: Versions prior to 0.2.0 were released under the LGPLv3+. Upon becoming a GNU project, it was relicensed under the GPLv3+ to help the FSF stand strong in its fight against proprietary JavaScript. For more information, please see the NEWS file (which can be built with make NEWS).