Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement C# access modifiers in javascript?

  • Summary

    I tried to achieve inheritance and encapsulation properly in javascript like it was in a class-based language such as c#.

    The ugly part is the protected members have multiple copies in the private instances which are only accessible via closure, and I don't have an idea except refreshing those members to the private instances.

    If it is possible, I want to get rid of both transmit and transfer in my code of Function.extend.

  • Update For people who are interested in citing or research, here's the source code repository:

    https://github.com/kenkins/Function.extend

  • The story

    Since assemblies may be a concept which is out of range of javascript, I don't take the internal modifier into account, but public, protected and private.

    public and private modifiers are not that difficult to achieve; but with inheritance, protected is significantly tricky. Yet it's not a recommended thing to do with javascript, most of articles I've read says prefix with a special character and document it.

    But it seems I'm persisted to make javascript to simulate class-based languages .. I stole this idea and implemented in my way, the code is at rear of this post.

    The idea behind the scene is to put higher accessibility with a higher prototype and access the highest one with a closure.

    Say we have three prototypes A, D and G, it looks like

    BANxt.png

    As it is not possible that an object is an instance of a type also of another type which is not in the prototype chain; the way I chosen is to chain the protected level horizontally and copy the members from the prototype of the declaring type. This makes nesting class possible, because the members declared on a less-derived type can be propagated to more-derived types; the transmit method in my code is to do this. If A, D and G have their own protected members, it would look like:

    bhcsI.png

    The closure for accessing the private instance, is this['']. It takes an argument which is for identifying a class. The modifiers holder is just the class identifier, named y in Function.extend and _ in the test code, it should not be exposed outside the class declaration. It is also used as a shortcut of this[''].

    _['base'] is in fact not only the base constructor invoker, but also the private instances creator. It creates the private instances and updates this[''] for each constructor with the inheritance, so it should always be called in the constructors.

    Although a private instance would have the access of the public members, it should not be used to alter them, since this[''] is not guaranteed to be invoked when accessing public members. But the accessing of private instance is; recent remembers the most recently accessed private instance, and update the protected members if there're changes.

    My question is, how can I get rid of this kind of refreshing the protected members? Are there better ideas to achieve the encapsulation more of the realistic?

    p.s.: I actually do not want a solution which uses non-standard methods/properties .. and it would be better there're polyfills if the used methods/properties are too fashion to the old browsers.


  • Function.extend

    Function.extend=function(base, factory) {     factory.call(initializeClass);     updateStaticMembersOfDerivedInnerClasses(y['public'].constructor);     transfer(y['protected'], y['public']);     return y['public'].constructor;      function y($this) {         return $this[''](y);     }      function transfer(target, source, descriptor) {         if(target!==source?             'undefined'!==typeof target?                 'undefined'!==typeof source:                     false:false) {             var keys='undefined'!==typeof descriptor? descriptor:source;              for(var key in keys) {                 if(Object.prototype.hasOwnProperty.call(source, key)) {                     target[key]=source[key];                 }             }         }     }      function updateStaticMembersOfDerivedInnerClasses(outer) {         var member, inner;          for(var key in outer) {             if(Object.prototype.hasOwnProperty.call(outer, key)?                 (member=outer[key]) instanceof outer?                     outer!==(inner=member.constructor):                         false:false) {                 transfer(inner, outer);             }         }     }      function initializeInstance() {         var $this=Object.create(y['private']);         var derivedGet=this[''];         var recent=$this;          this['']=function(x) {             var value=y!==x? derivedGet.call(this, x):$this;              if(value!==recent) {                 transfer(value, recent, x['protected']);                 recent=value;             }              transfer(value, this);             return value;         };          base.apply(this, arguments);         $this['']=this[''];     }      function initializeClass(derived) {         y['public']=Object.create(base.prototype);         y['public'].constructor=derived;          if(Object.prototype.hasOwnProperty.call(base, 'transmit')) {             base.transmit(y);         }         else {             y['protected']=Object.create(y['public']);         }          y['private']=Object.create(y['protected']);         y['base']=initializeInstance;         transfer(derived, base);          derived.transmit=function(x) {             if(x['public'] instanceof derived) {                 x['protected']=Object.create(y['protected']);                 x['protected'].constructor=x['public'].constructor;             }         };          derived.prototype=y['public'];         return y;     } }; 
  • test code

    'use strict';  var BaseClass=Function.extend(Object, function () {     var _=this(BaseClass);      var NestedClass=Function.extend(BaseClass, function () {         var _=this(NestedClass);          function NestedClass(x, y, z) {             _['base'].apply(this, arguments);             _(this).Y=y;             _(this).Z=z;         }          _['public'].SetX=function (x) {             _(this).InternalSetX(x);         };          _['public'].GetX=function () {             return _(this).InternalGetX();         };          _['public'].GetY=function () {             return _(this).Y;         };          _['public'].SetZ=function (z) {             _(this).Z=z;         };          _['public'].GetZ=function () {             return _(this).Z;         };          _['private'].Y=0;     });      function BaseClass(x) {         _['base'].apply(this, arguments);         _(this).X=x;     }      _['protected'].InternalSetX=function (x) {         _(this).X=x;     };      _['protected'].InternalGetX=function () {         return _(this).X;     };      _['private'].X=0;     _['protected'].Z=0;      BaseClass.Sample=new NestedClass(1, 2, 3); });  var DerivedClass=Function.extend(BaseClass, function () {     var _=this(DerivedClass);      function DerivedClass(x, y, z) {         _['base'].apply(this, arguments);     } });  var o=DerivedClass.Sample; alert(o.GetX()); alert(o.GetY()); alert(o.GetZ()); o.SetX(3); o.SetZ(1); alert(o.GetX()); alert(o.GetY()); alert(o.GetZ()); 
like image 596
Ken Kin Avatar asked Jan 14 '14 23:01

Ken Kin


People also ask

How is C implemented?

A standard conforming C implementation consists of a compiler that translates compilation units as mandated by the standard, an implementation of the standard library for all functions required by the standard and something (normally a linker) that puts everything together to build an executable file.

How do I start learning C?

Get started with C. Official C documentation - Might be hard to follow and understand for beginners. Visit official C Programming documentation. Write a lot of C programming code - The only way you can learn programming is by writing a lot of code.


2 Answers

I also had a similar thought and decided to try write something. A vanilla js solution. Still early but I like what came out of it. You might find it interesting also.

It's not exactly c# but provides a more strict ecosystem. And some other advanced js features in a lightweight solution.

https://github.com/iamlothian/rucksack.js

This is not a solution to your code, but solution to your concept. If your goal was the get your idea to work then by all means continue as I am interested by the result.

If you like me just want a more structured js environment, then here is one I wrote with similar ambition to your questions concepts.

Part 2:

The idea here is to use closure and access restriction to create a pattern that restricts the way code can be used and changed after is has been defined. For the most part a lot of the hard work has been done. But the pattern is left for you to define.

Here is a quick mock example demonstrating how you might implement a public|protect|private inheritance. I am trying to decide weather i implement some of this as a built in feature or leave it up to users to implement their own object extension like i have in the example.

http://plnkr.co/edit/ao2hTyBV1b3nYIwr7ZS5

The implementation is in scripts.js. view you console to see what is going on.

What rucksack provides is a framework for creating detached modules of code. These modules are grouped into namespaces and can depend on each other. These dependencies are resolved lazily as defined, so that definition order is not really important. The resolution process provides some other useful features such as interfaces matching and sealed module.

current features:

  • Modular
  • Dependency Injection
  • Factory constructor (Instances Object)
  • Service constructor (Static Objects)
  • Lazy loading
  • Easy error logging (All error within modules are captured and can be passed on)
  • Namespaces
  • Sealable modules and namespaces (modules that can't be accessed from outside the namespace)
  • Global await event for module
  • Interface for optional config object
  • Optional strict interface checks for injection
like image 55
Matthew.Lothian Avatar answered Oct 09 '22 18:10

Matthew.Lothian


While the code with closure might solve what you want, I would go with the simpler Privileged methods as Crockford called them here.

Usage idea is simple:

  • Define privileged method on the base object (with limit 1 - allows to be called only once).
  • Privileged method returns a protected interface of itself (of a base object) which contains protected functions in it (probably those functions are privately defined in the base, and then get copied over to the protected interface object... or maybe the protected interface exists privately).
  • Each object extends its protected interface with its base object's protected interface and still exposes it through the privileged method.

You will end up with something like this:

function A() {     var protected = {         protectedA: function() { }     };      this.getProtected = (function() {         var allow = true;          //privileged function.         return function() {             if (allow) {                 allow = false;                 return protected;             }         };     }); }  //B - derives from (extends) A function B() {     var base = {}; //acquiring a base omitted - depends on your implementation.      var protected = {         protectedB: function() { }     };     //"extend" simply copies new members into protected:     protected = $.extend(protected, base.getProtected());       this.getProtected = function() {          /* privileged function - similar to A.getProtected */      }; } 

JavaScript has limited abilities in this extent, so the protected sugar comes with some cost anyway.

like image 44
Tengiz Avatar answered Oct 09 '22 16:10

Tengiz