Hi all,
I like not to be forced to write setters and getters - and hence the idea of a config object that populates its own functions. However the current implementation has a problem imho with the fact that it places non-primitive Objects (like arrays and {}) in the prototype. Problems soon arise when multiple instance of the same class are being created...

This is an attempt to provide a fix:
- only primitive, functions or null configs are put in the prototype.
- instead of using 'set/get' + configName, the setter and getters are just functions with the same name of the config. When called with an arguments, it will be the setter (returning this), without arguments, the getter. It is faster to write, and allows method chaining (see example below).
- for types other than primitive, the configs are applied only the first time the setter/getter is called. The default config is still available, but it is applied to the instance and not the Class.
- apply and updates functions work as without the fix.

Use like this:
Code:
Ext.define('MyChart', {  
  extend: 'Ext.chart.Chart',  
  config: {
     width: 100,
     heigth: 100,
     anArray: [],
     anObject: {}
     },   ...
and later: myChart.width(200).height(250) to set width and height or myChart.width() to get the width.

The other side effect is that initConfig method does not need to be called for this to work (as long as you access you configs with the created getter)

Cheers,
C.

Fix:
Code:
(function() {
var  ExtClass = Ext.Class,
        prefix = "",
        config,
        prototype,
        data;

    function applyClass(config) {
          Ext.Object.each(config,function(name, value) { 
            name = prefix + name; 
            var nameMap = ExtClass.getConfigNameMap(name),
                internalName = nameMap.internal,
                primitiveName = nameMap.primitive,
                initializedName = nameMap.initialized,
                applyName = nameMap.apply,
                updateName = nameMap.update,
                setName = nameMap.set,
                getName = nameMap.get,
                hasOwnSetter = (setName in prototype) || data.hasOwnProperty(setName),
                hasOwnApplier = (applyName in prototype) || data.hasOwnProperty(applyName),
                hasOwnUpdater = (updateName in prototype) || data.hasOwnProperty(updateName),
                optimizedGetter, customGetter,
                //added
                changeName = nameMap.changeEvent, 
                isFn = Ext.isFunction(value),
                isPrimitive = (value === null || Ext.isPrimitive(value) || isFn),
                
                fnName = nameMap.fn,
                hasOwnFn = (fnName in prototype) || data.hasOwnProperty(fnName);


            //if (value === null || (!hasOwnSetter && !hasOwnApplier && !hasOwnUpdater)) {
            if(isPrimitive){    
                prototype[internalName] = value;
                prototype[primitiveName] = true;
                prototype[initializedName] = true;
            }
            else {
                prototype[primitiveName] = false;
                prototype[initializedName] = false;
            }


            if (!hasOwnSetter && !isFn) {
                data[setName] = function(value) {
                    var oldValue = this[internalName],
                        applier = this[applyName],
                        updater = this[updateName];


                    if (!this[initializedName]) {
                        this[initializedName] = true;
                    }


                    if (applier) {
                        value = applier.call(this, value, oldValue);
                    }


                    if (typeof value != 'undefined') {
                        this[internalName] = value;
                        if (updater && value !== oldValue) {
                            updater.call(this, value, oldValue);
                        }
                    }
                    return this;
                };
            }


            if (!(getName in prototype) || data.hasOwnProperty(getName)) {
                customGetter = data[getName] || false;


                if (customGetter) {
                    optimizedGetter = function() {
                        return customGetter.apply(this, arguments);
                    };
                }
                else {
                    optimizedGetter =
                        isFn ? function() {return  this[internalName]()} 
                        : function() {return  this[internalName]};
                }


                data[getName] = function() {
                    var currentGetter;


                    if (!this[initializedName]) {
                        this[initializedName] = true;
                        this[setName](this.config[name]);
                    }


                    currentGetter = this[getName];


                    if ('$previous' in currentGetter) {
                        currentGetter.$previous = optimizedGetter;
                    }
                    else {
                        this[getName] = optimizedGetter;
                    }
                    
                    return optimizedGetter.apply(this, arguments);
                };
            }
         if(!hasOwnFn) {
                data[fnName] = function() {
                    if(arguments.length) {
                        this[initializedName] = true;
                        return (this.isModel && this.fields.map[fnName]) 
                            ? this.set(fnName, arguments[0])
                            : this[setName].apply(this, arguments)
                        }
                    if(!this[primitiveName]){    
                        if(!this.hasOwnProperty(this[initializedName])) {
                           this[setName](Ext.clone(this.getConfig(fnName))); 
                           this[initializedName] = true;
                             }
                        }
                    return optimizedGetter.apply(this, arguments) 
                    }
           };
         })
    };
        
    ExtClass.getConfigNameMap= function(name) {
            var cache = this.configNameCache,
                map = cache[name],
                capitalizedName;


            if (!map) {
                capitalizedName = name.charAt(0).toUpperCase() + name.substr(1);
 
                map = cache[name] = {
                    internal: '__' + name + '__', 
                    fn: name,
                    initialized: '_is' + capitalizedName + 'Initialized',
                    primitive: '_is' + capitalizedName + 'Primitive',
                    apply: 'apply' + capitalizedName,
                    update: 'update' + capitalizedName,
                    'set': 'set' + capitalizedName,
                    'get': 'get' + capitalizedName,
                    doSet : 'doSet' + capitalizedName,
                    changeEvent: name.toLowerCase() + 'change'
                };
            }


            return map;
        }
    ExtClass.getPreprocessor('config').fn = function(Class, dt){
            data = dt;
            config = data.config;
            prototype = Class.prototype;


        delete data.config;
        applyClass(config);
        Class.addConfig(config, true);
    }   
   Ext.override(Ext.base,{
    initConfig : function(config) {
        this.callParent([config]);
        var  hasConfig = this.configMap;
        for (name in config) {
                if (hasConfig[name]) { delete config[name]}
                }
        return this
        }
   })
}());