sylvainpolletvillard / ObjectModel

Strong Dynamically Typed Object Modeling for JavaScript
http://objectmodel.js.org
MIT License
467 stars 30 forks source link

Proposal: rework default assignments #93

Closed sylvainpolletvillard closed 5 years ago

sylvainpolletvillard commented 6 years ago

Defaults assignments need a rework for v4.

What is needed ?

v3 issues

Proposed solutions

gotjoshua commented 6 years ago

@gibelium and I would like to engage in this proposal, but we are quite uncertain about what you mean with your second proposal point:

deep merge object models defaults at instanciation instead of using their prototypes

could you offer more explanation and maybe some psedo code examples of how v4 could feel different with the new proposals?

would you offer backward compatibility to 3.x or will full refactoring of defaults be needed?

sylvainpolletvillard commented 6 years ago

Sure. In v3, we use prototypes to store defaults values:

M = Model({ x: Number }).defaults({ x: 42 })

is roughly equivalent to

M = data => Object.assign(Object.create({ x: 42 }), data)

so we can do this:

m = M({ x: 99 })
console.log(m.x) // 99
delete m.x;
console.log(m.x) // 42 (taken from prototype)

This is pretty cool but not a very common used feature. Actually, most JS developers don't even know how prototypal inheritance works.

Most users instead think of defaults as a one-time fill-in-the-gaps at object instanciation. Somethink like this: M = data => Object.assign({ x: 42 }, data)

I personally think this is less elegant, but if it's easier to reason about and more useful to the users, I'm okay to switch to this behaviour for v4. This will be closer to the defaultTo behaviour which is simply a default value assignement when constructor is called without args.

So this change will enable to merge defaults and defaultTo into a single method, huge win for simplicity. That also means this will be a breaking change and you'll need to change your code. This is why I keep this for v4

sylvainpolletvillard commented 5 years ago

Update: I tried different syntaxes to pass a function for default values, but none was satisfying. So I decided that the library should take care of this for you, and dereference the default value at each model instanciation. This prevent users to explicitely set the default value to a common reference, but I can't think of any valid usecase for this.

The current plan is to remove ObjectModel defaults method and replace it by defaultTo without changes in the method signature.

RichAyotte commented 5 years ago

Is there a way to set a default prototype? The following doesn't seem to work.

const {EventEmitter} = require('events')
const Crypto = ObjectModel({
  name: String
}).defaultTo(EventEmitter.prototype)

I'm setting the prototype as follows but it would be nice to have a default.

Object.setPrototypeOf(
  Crypto({
    name: 'Tezos'
  })
  , EventEmitter.prototype
)
sylvainpolletvillard commented 5 years ago

@RichAyotte lets discuss in a new issue: https://github.com/sylvainpolletvillard/ObjectModel/issues/104