Index: tinypy/ops.c
===================================================================
--- tinypy/ops.c	(revision 49)
+++ tinypy/ops.c	(working copy)
@@ -1,13 +1,3 @@
-#define TP_META_BEGIN(self,name) \
-    if (self.dict.dtype && self.dict.val->meta.type != TP_NONE) { \
-        int n = _tp_dict_find(tp,self.dict.val->meta.dict.val,tp_string(name)); \
-        if (n != -1) { \
-            tp_obj meta = self.dict.val->meta.dict.val->items[n].val;
-
-#define TP_META_END \
-        } \
-    }
-
 tp_obj tp_str(TP,tp_obj self) {
     int type = self.type;
     if (type == TP_STRING) { return self; }
@@ -80,8 +70,9 @@
     tp_obj r;
     if (type == TP_DICT) {
         TP_META_BEGIN(self,"__get__");
-            return tp_call(tp,meta,tp_params_v(tp,2,self,k));
+            return tp_call(tp,meta,tp_params_v(tp,1,k));
         TP_META_END;
+        if (self.dict.dtype && _tp_lookup(tp,self,k,&r)) { return r; }
         return _tp_dict_get(tp,self.dict.val,k,"tp_get");
     } else if (type == TP_LIST) {
         if (k.type == TP_NUMBER) {
@@ -176,7 +167,7 @@
 
     if (type == TP_DICT) {
         TP_META_BEGIN(self,"__set__");
-            tp_call(tp,meta,tp_params_v(tp,3,self,k,v));
+            tp_call(tp,meta,tp_params_v(tp,2,k,v));
             return;
         TP_META_END;
         _tp_dict_set(tp,self.dict.val,k,v);
Index: tinypy/encode.py
===================================================================
--- tinypy/encode.py	(revision 49)
+++ tinypy/encode.py	(working copy)
@@ -470,6 +470,7 @@
     parent = None
     if items[0].type == 'name':
         name = items[0].val
+        parent = Token(tok.pos,'name','object')
     else:
         name = items[0].items[0].val
         parent = items[0].items[1]
@@ -480,22 +481,15 @@
     code(GSET,ts,kls)
     free_tmp(ts) #REG
     
-    if parent:
-        free_tmp(do(Token(tok.pos,'symbol','=',[
-            Token(tok.pos,'get',None,[
-                Token(tok.pos,'reg',kls),
-                Token(tok.pos,'string','__parent__')]),
-            parent])))
-
+    free_tmp(do(Token(tok.pos,'call',None,[
+        Token(tok.pos,'name','setmeta'),
+        Token(tok.pos,'reg',kls),
+        parent])))
+        
     for fc in items[1].items:
         if fc.type != 'def': continue
         do_def(fc,kls)
         
-    free_tmp(do(Token(tok.pos,'call',None,[
-        Token(tok.pos,'name','setmeta'),
-        Token(tok.pos,'reg',kls),
-        Token(tok.pos,'name','ClassMeta')])))
-    
     free_reg(kls) #REG
 
 
Index: tinypy/tests.py
===================================================================
--- tinypy/tests.py	(revision 49)
+++ tinypy/tests.py	(working copy)
@@ -442,13 +442,6 @@
 """
 ,"OK")
 
-    t_render("""
-class C:
-    def __init__(self,data): self.data = data
-    def print(self): print(self.data)
-C("OK").print()
-"""
-,"OK")
 
     t_render("""
 x = [v*v for v in range(0,5)]
@@ -582,22 +575,6 @@
 print(x)
 ""","OK")
 
-    t_render("""
-class X:
-    pass
-y = X()
-print("OK")
-""","OK")
-
-    t_render("""
-class X: pass
-def test(): y = X()
-test()
-print("OK")
-""","OK")
-
-    t_render(["class X: pass\ndef test(): y = X()","import tmp1\ntmp1.test();print('OK')"],"OK")
-    
     t_render("print(len([1,2,3]))","3")
     
     t_render('if not "?" in "xyz": print("OK")',"OK")
@@ -637,30 +614,8 @@
 
     #t_render("def test(): print('OK')\n{'__call__':test}()","OK")
 
-    t_render("""
-class A:
-    def __init__(self):
-        self.a = 'O'
-        self.b = 'x'
-    def test(self):
-        print("KO")
-class B(A):
-    def __init__(self):
-        A.__init__(self)
-        self.b = 'K'
-    def test(self):
-        print(self.a+self.b)
-B().test()
-""","OK")
 
     t_render("""
-class A:
-    def test(self):
-        print(self)
-A.test("OK")
-""","OK")
-
-    t_render("""
 def test():
     def fnc():
         print("OK")
@@ -722,39 +677,28 @@
     t_render("""
 def get(self,k):
     return k+"K"
-m = {"__get__":get}
-v = {}
-setmeta(v,m)
+v = object()
+v.__get__ = bind(get,v)
 print(v.O)
-"""
-,"OK")
+""",
+"OK")
 
     t_render("""
 def set(self,k,v):
     self = getraw(self)
     self[k] = v + "K"
-m = {"__set__":set}
-v = {}
-setmeta(v,m)
+v = object()
+v.__set__ = bind(set,v)
 v.x = "O"
 print(v.x)
-"""
-,"OK")
-
-    t_render("""
-m = {"test":"OK"}
-v = {}
-setmeta(v,m)
-print(getmeta(v)["test"])
 """,
 "OK")
 
     t_render("""
 def call(self,x):
     print(x)
-m = {"__call__":call}
-v = {}
-setmeta(v,m)
+v = object()
+v.__call__ = bind(call,v)
 v("OK")
 """
 ,"OK")
@@ -769,24 +713,12 @@
 print("OK")
 ""","OK")
 
-
     meta_objs_init = """
-def MyObj_bind(klass,self):
-    if '__parent__' in klass:
-        MyObj_bind(klass.__parent__,self)
-    for k in klass:
-        v = klass[k]
-        if istype(v,'fnc'):
-            self[k] = bind(v,self)
-        else:
-            self[k] = v
-def MyObj_call(klass,*p):
-    self = {}
-    MyObj_bind(klass,self)
-    if '__init__' in self:
-        self.__init__(*p)
+def my_new(klass,*p):
+    self = object()
+    setmeta(self,klass)
+    self.__init__(*p)
     return self
-MyObj = {'__call__':MyObj_call}
 
 def A_init(self,v):
     if v: print("A_init")
@@ -794,16 +726,14 @@
     print("A_test1")
 def A_test2(self):
     print("A_test2")
-A = {'__init__':A_init,'test1':A_test1,'test2':A_test2}
-setmeta(A,MyObj)
+A = {'__new__':my_new,'__init__':A_init,'test1':A_test1,'test2':A_test2}
 
 def B_init(self,v):
     if v: print("B_init")
 def B_test2(self):
     print("B_test2")
-B = {'__parent__':A,'__init__':B_init,'test2':B_test2}
-setmeta(B,MyObj)
-
+B = {'__init__':B_init,'test2':B_test2}
+setmeta(B,A)
 """
 
     t_render(meta_objs_init+"""A(True)""","A_init")
@@ -813,22 +743,85 @@
     t_render(meta_objs_init+"""B(False).test1()""","A_test1")
     t_render(meta_objs_init+"""B(False).test2()""","B_test2")
 
-    #test that you can make a callable meta object
+    #various class construct use tests
     t_render("""
-class TestMeta:
+class C:
+    def __init__(self,data): self.data = data
+    def print(self): print(self.data)
+C("OK").print()
+"""
+,"OK")
+
+    t_render("""
+class X:
+    pass
+y = X()
+print("OK")
+""","OK")
+
+    t_render("""
+class X: pass
+def test(): y = X()
+test()
+print("OK")
+""","OK")
+
+    t_render(["class X: pass\ndef test(): y = X()","import tmp1\ntmp1.test();print('OK')"],"OK")
+
+    t_render("""
+class A:
+    def __init__(self):
+        self.a = 'O'
+        self.b = 'x'
+    def test(self):
+        print("KO")
+class B(A):
+    def __init__(self):
+        A.__init__(self)
+        self.b = 'K'
+    def test(self):
+        print(self.a+self.b)
+B().test()
+""","OK")
+
+    t_render("""
+class A:
+    def test(self):
+        print(self)
+A.test("OK")
+""","OK")
+
+
+    #test that you can make a callable object
+    t_render("""
+class Test:
+    def __init__(self,v):
+        self.value = v
     def __call__(self):
-        self = getraw(self)
         print(self.value)
 
-class Test:
-    def __init__(self,value):
-        self.value = value
-        setmeta(self,TestMeta)
-
 x = Test('OK')
 x()
 ""","OK")
 
+    #test that you can use a __get__
+    t_render("""
+class Test:
+    def __get__(self,k):
+        return k+"K"
+x = Test()
+print(x.O)
+""","OK")
+    #test that you can use __set__
+    t_render("""
+class Test:
+    def __set__(self,k,v):
+        getraw(self)[k] = "O"+v
+x = Test()
+x.v = "K"
+print(x.v)
+""","OK")
+
     #test that exceptions are cleared after they are caught
     #and not repeated
     t_render("""
@@ -845,6 +838,35 @@
     pass
 ""","OK")
 
+    #check that missing attributes throw an error
+    t_render("""
+class A: pass
+try:
+    A().x
+except:
+    print('OK')
+""","OK")
+
+    #check that a changed attribute gets changed
+    t_render("""
+class A:
+    def x(self): pass
+a = A()
+a.x = "OK"
+print(a.x)
+""","OK")
+    
+    #test that you can use a __get__ gets inherited
+    t_render("""
+class A:
+    def __get__(self,k):
+        return k+"K"
+class B(A):
+    pass
+x = B()
+print(x.O)
+""","OK")
+
 ################################################################################
 
 def t_boot(ss,ex,exact=True):
@@ -969,11 +991,9 @@
     
     /* create our class */
     tp_obj tmp;
-    tp_obj A = tp_dict(tp);
+    tp_obj A = tp_class(tp);
     tp_set(tp,A,tp_string("__init__"),tp_fnc(tp,A_init));
     tp_set(tp,A,tp_string("test"),tp_fnc(tp,A_test));
-    tp_params_v(tp,2,A,tp_get(tp,tp->builtins,tp_string("ClassMeta")));
-    tp_setmeta(tp);
     
     /* instantiate it and call test */
     tmp = tp_call(tp,A,tp_params_v(tp,1,tp_string("OK")));
Index: tinypy/vm.c
===================================================================
--- tinypy/vm.c	(revision 49)
+++ tinypy/vm.c	(working copy)
@@ -105,10 +105,16 @@
     tp->params = params;
     
     if (self.type == TP_DICT) {
-        TP_META_BEGIN(self,"__call__");
-            _tp_list_insert(tp,params.list.val,0,self);
-            return tp_call(tp,meta,params);
-        TP_META_END;
+        if (self.dict.dtype == 1) {
+            TP_META_BEGIN(self,"__new__");
+                _tp_list_insert(tp,params.list.val,0,self);
+                return tp_call(tp,meta,params);
+            TP_META_END;
+        } else if (self.dict.dtype == 3) {
+            TP_META_BEGIN(self,"__call__");
+                return tp_call(tp,meta,params);
+            TP_META_END;
+        }
     }
     if (self.type == TP_FNC && !(self.fnc.ftype&1)) {
         tp_obj r = _tp_tcall(tp,self);
@@ -334,6 +340,7 @@
 }
 
 void tp_builtins(TP) {
+    tp_obj o;
     struct {const char *s;void *f;} b[] = {
     {"print",tp_print}, {"range",tp_range}, {"min",tp_min},
     {"max",tp_max}, {"bind",tp_bind}, {"copy",tp_copy},
@@ -343,19 +350,18 @@
     {"load",tp_load}, {"fpack",tp_fpack}, {"abs",tp_abs},
     {"int",tp_int}, {"exec",tp_exec_}, {"exists",tp_exists},
     {"mtime",tp_mtime}, {"number",tp_float}, {"round",tp_round},
-    {"ord",tp_ord}, {"merge",tp_merge}, {"setmeta",tp_setmeta},
-    {"getraw",tp_getraw}, {"getmeta",tp_getmeta},
+    {"ord",tp_ord}, {"merge",tp_merge}, {"getraw",tp_getraw},
+    {"setmeta",tp_setmeta}, {"getmeta",tp_getmeta},
     {0,0},
     };
     int i; for(i=0; b[i].s; i++) {
         tp_set(tp,tp->builtins,tp_string(b[i].s),tp_fnc(tp,(tp_obj (*)(tp_vm *))b[i].f));
     }
     
-    /*
-    BUILTINS['ClassMeta'] = {'__call__':ClassMeta_call}
-    */
-    tp_set(tp,tp->builtins,tp_string("ClassMeta"),tp_dict_n(tp,1,(tp_obj[]){tp_string("__call__"),tp_fnc(tp,tp_ClassMeta_call)}));
-
+    o = tp_object(tp);
+    tp_set(tp,o,tp_string("__call__"),tp_fnc(tp,tp_object_call));
+    tp_set(tp,o,tp_string("__new__"),tp_fnc(tp,tp_object_new));
+    tp_set(tp,tp->builtins,tp_string("object"),o);
 }
 
 
Index: tinypy/tp.h
===================================================================
--- tinypy/tp.h	(revision 49)
+++ tinypy/tp.h	(working copy)
@@ -183,6 +183,7 @@
 
 void tp_set(TP,tp_obj,tp_obj,tp_obj);
 tp_obj tp_get(TP,tp_obj,tp_obj);
+tp_obj tp_has(TP,tp_obj self, tp_obj k);
 tp_obj tp_len(TP,tp_obj);
 tp_obj tp_str(TP,tp_obj);
 int tp_cmp(TP,tp_obj,tp_obj);
Index: tinypy/builtins.c
===================================================================
--- tinypy/builtins.c	(revision 49)
+++ tinypy/builtins.c	(working copy)
@@ -89,7 +89,8 @@
     if (strcmp("list",t) == 0) { return tp_number(v.type == TP_LIST); }
     if (strcmp("dict",t) == 0) { return tp_number(v.type == TP_DICT); }
     if (strcmp("number",t) == 0) { return tp_number(v.type == TP_NUMBER); }
-    if (strcmp("fnc",t) == 0) { return tp_number(v.type == TP_FNC); }
+    if (strcmp("fnc",t) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) == 0); }
+    if (strcmp("method",t) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) != 0); }
     tp_raise(tp_None,"is_type(%s,%s)",TP_CSTR(v),t);
 }
 
@@ -173,6 +174,29 @@
     tp_raise(tp_None,"tp_mtime(%s)",s);
 }
 
+int _tp_lookup(TP,tp_obj self, tp_obj k, tp_obj *meta) {
+    int n = _tp_dict_find(tp,self.dict.val,k);
+    if (n != -1) {
+        *meta = self.dict.val->items[n].val;
+        return 1;
+    }
+    if (self.dict.dtype && self.dict.val->meta.type == TP_DICT && _tp_lookup(tp,self.dict.val->meta,k,meta)) {
+        if (self.dict.dtype == 3 && meta->type == TP_FNC) {
+            *meta = tp_fnc_new(tp,meta->fnc.ftype|2,meta->fnc.val,self,meta->fnc.info->globals);
+        }
+        return 1;
+    }
+    return 0;
+}
+
+#define TP_META_BEGIN(self,name) \
+    if (self.dict.dtype) { \
+        tp_obj meta; if (_tp_lookup(tp,self,tp_string(name),&meta)) {
+
+#define TP_META_END \
+        } \
+    }
+    
 tp_obj tp_setmeta(TP) {
     tp_obj self = TP_TYPE(TP_DICT);
     tp_obj meta = TP_TYPE(TP_DICT);
@@ -185,68 +209,42 @@
     return self.dict.val->meta;
 }
 
-tp_obj tp_getraw(TP) {
-    tp_obj self = TP_TYPE(TP_DICT);
-    self.dict.dtype = 0;
+tp_obj tp_object(TP) {
+    tp_obj self = tp_dict(tp);
+    self.dict.dtype |= 2;
     return self;
 }
-    
-    
-/*
-def ClassMeta_bind(klass,self):
-*/
-tp_obj tp_has(TP,tp_obj self, tp_obj k) ;
-void tp_ClassMeta_bind(TP,tp_obj klass,tp_obj self) {
-    int i;
-    
-    /*
-    if '__parent__' in klass:
-        ClassMeta_bind(klass.__parent__,self)
-    */
-    
-    if (tp_has(tp,klass,tp_string("__parent__")).number.val) {
-        tp_ClassMeta_bind(tp,tp_get(tp,klass,tp_string("__parent__")),self);
-    }
-    
-    /*
-    for k in klass:
-        v = klass[k]
-        if istype(v,'fnc'):
-            self[k] = bind(v,self)
-        else:
-            self[k] = v
-    */
-    
-    for (i=0; i<klass.dict.val->len; i++) {
-        int n = _tp_dict_next(tp,klass.dict.val);
-        tp_obj k = klass.dict.val->items[n].key;
-        tp_obj v = klass.dict.val->items[n].val;
-        if (v.type == TP_FNC) {
-            tp_set(tp,self,k,tp_fnc_new(tp,v.fnc.ftype|2,v.fnc.val,self,v.fnc.info->globals));
-        } else {
-            tp_set(tp,self,k,v);
-        }
-    }
-}
 
-/*
-def ClassMeta_call(klass,*p):
-*/
-tp_obj tp_ClassMeta_call(TP) {
+tp_obj tp_object_new(TP) {
     tp_obj klass = TP_TYPE(TP_DICT);
-    
-    /*
-    self = {}
-    ClassMeta_bind(klass,self)
-    if '__init__' in self:
-        self.__init__(*p)
-    return self
-    */
-    tp_obj self = tp_dict(tp);
-    tp_ClassMeta_bind(tp,klass,self);
-    if (tp_has(tp,self,tp_string("__init__")).number.val) {
-        tp_call(tp,tp_get(tp,self,tp_string("__init__")),tp->params);
+    tp_obj self = tp_object(tp);
+    self.dict.val->meta = klass;
+    TP_META_BEGIN(self,"__init__");
+        tp_call(tp,meta,tp->params);
+    TP_META_END;
+    return self;
+}
+
+tp_obj tp_object_call(TP) {
+    tp_obj self;
+    if (tp->params.list.val->len) {
+        self = TP_TYPE(TP_DICT);
+        self.dict.dtype |= 2;
+    } else {
+        self = tp_object(tp);
     }
     return self;
 }
 
+tp_obj tp_getraw(TP) {
+    tp_obj self = TP_TYPE(TP_DICT);
+    self.dict.dtype = 0;
+    return self;
+}
+
+tp_obj tp_class(TP) {
+    tp_obj klass = tp_dict(tp);
+    klass.dict.val->meta = tp_get(tp,tp->builtins,tp_string("object")); 
+    return klass;
+}
+
Index: tinypy/gc.c
===================================================================
--- tinypy/gc.c	(revision 49)
+++ tinypy/gc.c	(working copy)
@@ -30,7 +30,7 @@
             tp_grey(tp,v.dict.val->items[n].key);
             tp_grey(tp,v.dict.val->items[n].val);
         }
-        tp_grey(tp,v.dict.val->meta);
+        tp_grey(tp,v.dict.val->meta); 
     }
     if (type == TP_FNC) {
         tp_grey(tp,v.fnc.info->self);
