Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

private variables #8

Open
opcodewriter opened this issue Apr 1, 2016 · 5 comments
Open

private variables #8

opcodewriter opened this issue Apr 1, 2016 · 5 comments

Comments

@opcodewriter
Copy link

any example of private variables in a trait?

@maiermic
Copy link

maiermic commented Apr 1, 2016

There is no special build-in way. You can use lexical scoping, which is a common way in JavaScript to hide information.

Example (run it online)

function MakeTraitWithPrivateProperty(privateProperty) {
  return Trait({
    publicProperty: function () {
      // do something with privateProperty
      console.log("internal access: " + privateProperty)
    }
  })
}

var obj = Trait.create(
  Object.prototype,
  MakeTraitWithPrivateProperty(42)
);

console.log("external access: " + obj.privateProperty); // external access: undefined
obj.publicProperty(); // internal access: 42

The examples already cover this approach.

@opcodewriter
Copy link
Author

@maiermic thank you.
But what if you need state? I guess this would do it:

http://jsbin.com/dalexozohu/edit?js,console

function MakeTraitWithPrivateProperty(privateProperty) {
  return Trait({
    publicProperty: function () {
      // do something with privateProperty
      console.log("internal access: " + privateProperty);
    },
    add: function() {
      privateProperty += 1;
    }
  });
}

var obj = Trait.create(
  Object.prototype,
  MakeTraitWithPrivateProperty(42)
);

console.log("external access: " + obj.privateProperty); // external access: undefined
obj.publicProperty(); // internal access: 42
obj.add();
obj.publicProperty(); 

Is this an OK approach to have state? I can't think of any issues with this

@dotnetCarpenter
Copy link
Member

@opcodewriter This approach with getters and setters is a very common OOP technique but has been criticized.

@opcodewriter
Copy link
Author

@dotnetCarpenter thanks. but that's quite an article. I believe getters and setters are good for encapsulation.
anyway, what's the solution you recommend for my question?

@dotnetCarpenter
Copy link
Member

Your solution is fine just be aware of the following:

  1. privat variables does not have to be confined to argument variables. You can do:
function MakeTraitWithPrivateProperty() {
  var privateProperty = 42;
  return Trait({
    publicProperty: function () {
      // do something with privateProperty
      console.log("internal access: " + privateProperty);
    },
    add: function() {
      privateProperty += 1;
    }
  });
}
  1. Keep it simple. In OOP the Single Responsibility Principle (SRP), states that a class should only have one reason to change, which means that if you set an object which is by itself a complex object, you can quickly create a god class that has too many responsibilities and is impossible to refactor. In that case you should be using trait composition.
  2. If you set objects in JS you are passing a reference to that object and not the object itself. Since the trait example in your example holds a reference to that object in one or more of it's methods (which is stored in the heap), that object will probably never be freed, even when the resulting object from MakeTraitWithPrivateProperty goes out of scope or even is nullified. Which will result in a memory leak.
var obj1 = MakeTraitWithPrivateProperty();
// do stuff with obj1
obj1.add(complexObject);
obj1 = null; // a private variable reference can still exist to `complexObject`

The work-around is to define a destroy method that nullifies all internal references.

Conclusion

You can use setter/getters but try to restrict yourself to primitive values, which are passed by-value (as oppose to by-reference). In JS primitives are, Number, String and Boolean.
If you find yourself in need to hold a reference to objects in order to do object composition, you should see if you can use Trait.compose instead. If not then take a look at the Command pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants