diff --git a/src/opcodes.c b/src/opcodes.c
index b713d7dd2762cd8c4156e10b82a77c6243ba45b3..6410fc05c27aa1291eca812320c2e4a521760874 100644
--- a/src/opcodes.c
+++ b/src/opcodes.c
@@ -74,14 +74,176 @@ void f_index()
   pop_stack();
 }
 
+void cast(struct lpc_string *s)
+{
+  INT32 i;
+  
+  i=compile_type_to_runtime_type(s);
+
+  if(i != sp[-1].type)
+  {
+    if(i == T_MIXED) return;
+
+    if(sp[-2].type == T_OBJECT)
+    {
+      push_string(describe_type(s));
+      if(!sp[-2].u.object->prog)
+	error("Cast called on destructed object.\n");
+      if(sp[-2].u.object->prog->lfuns[LFUN_CAST] == -1)
+	error("No cast method in object.\n");
+      apply_lfun(sp[-2].u.object, LFUN_CAST, 1);
+      free_svalue(sp-2);
+      sp[-2]=sp[-1];
+      sp--;
+      return;
+    }
+
+    switch(i)
+    {
+    case T_MIXED:
+      break;
+
+    case T_INT:
+      switch(sp[-1].type)
+      {
+      case T_FLOAT:
+	i=(int)(sp[-1].u.float_number);
+	break;
+
+      case T_STRING:
+	i=strtol(sp[-1].u.string->str,0,0);
+	free_string(sp[-1].u.string);
+	break;
+      
+      default:
+	error("Cannot cast to int.\n");
+      }
+      
+      sp[-1].type=T_INT;
+      sp[-1].u.integer=i;
+      break;
+
+    case T_FLOAT:
+    {
+      FLOAT_TYPE f;
+      switch(sp[-1].type)
+      {
+      case T_INT:
+	f=(FLOAT_TYPE)(sp[-1].u.integer);
+	break;
+
+      case T_STRING:
+	f=STRTOD(sp[-1].u.string->str,0);
+	free_string(sp[-1].u.string);
+	break;
+      
+      default:
+	error("Cannot cast to float.\n");
+	f=0.0;
+      }
+      
+      sp[-1].type=T_FLOAT;
+      sp[-1].u.float_number=f;
+      break;
+    }
+
+    case T_STRING:
+    {
+      char buf[200];
+      switch(sp[-1].type)
+      {
+      case T_INT:
+	sprintf(buf,"%ld",(long)sp[-1].u.integer);
+	break;
+
+      case T_FLOAT:
+	sprintf(buf,"%f",(double)sp[-1].u.float_number);
+	break;
+      
+      default:
+	error("Cannot cast to string.\n");
+      }
+      
+      sp[-1].type=T_STRING;
+      sp[-1].u.string=make_shared_string(buf);
+      break;
+    }
+
+    case T_OBJECT:
+      switch(sp[-1].type)
+      {
+      case T_STRING:
+	APPLY_MASTER("cast_to_object",1);
+	break;
+	
+      case T_FUNCTION:
+	sp[-1].type = T_OBJECT;
+	break;
+      }
+      break;
+
+    case T_PROGRAM:
+      APPLY_MASTER("cast_to_program",1);
+      break;
+
+    case T_FUNCTION:
+    {
+      INT32 i;
+      if(fp->current_object->prog)
+	error("Cast to function in destructed object.\n");
+      i=find_shared_string_identifier(sp[-1].u.string,fp->current_object->prog);
+      free_string(sp[-1].u.string);
+      /* FIXME, check that it is a indeed a function */
+      if(i==-1)
+      {
+	sp[-1].type=T_FUNCTION;
+	sp[-1].subtype=i;
+	sp[-1].u.object=fp->current_object;
+	fp->current_object->refs++;
+      }else{
+	sp[-1].type=T_INT;
+	sp[-1].subtype=NUMBER_UNDEFINED;
+	sp[-1].u.integer=0;
+      }
+      break;
+    }
+
+    }
+  }
+}
+
 void f_cast()
 {
   INT32 i;
   
   i=compile_type_to_runtime_type(sp[-1].u.string);
-  pop_stack();
-  if(i != sp[-1].type)
+
+  if(i != sp[-2].type)
   {
+    if(i == T_MIXED)
+    {
+      pop_stack();
+      return;
+    }
+
+    if(sp[-2].type == T_OBJECT)
+    {
+      struct lpc_string *s;
+      s=describe_type(sp[-1].u.string);
+      pop_stack();
+      push_string(s);
+      if(!sp[-2].u.object->prog)
+	error("Cast called on destructed object.\n");
+      if(sp[-2].u.object->prog->lfuns[LFUN_CAST] == -1)
+	error("No cast method in object.\n");
+      apply_lfun(sp[-2].u.object, LFUN_CAST, 1);
+      free_svalue(sp-2);
+      sp[-2]=sp[-1];
+      sp--;
+      return;
+    }
+
+    pop_stack();
     switch(i)
     {
     case T_MIXED:
@@ -193,6 +355,8 @@ void f_cast()
     }
 
     }
+  }else{
+    pop_stack();
   }
 }
 
@@ -493,10 +657,10 @@ static INT32 low_sscanf(INT32 num_arg)
 
 	if(!contains_percent_percent)
 	{
-	  s=MEMMEM(end_str_start,
-		   end_str_end-end_str_start,
-		   input+eye,
-		   input_len-eye);
+	  s=my_memmem(end_str_start,
+		      end_str_end-end_str_start,
+		      input+eye,
+		      input_len-eye);
 	  if(!s) return matches;
 	  eye=s-input;
 	  new_eye=eye+end_str_end-end_str_start;
diff --git a/src/operators.c b/src/operators.c
index 9227d3b05a3d182ce27ac7fa0a9d21d255b8dbce..ecbe77f120c0ff121854367be59e66e7b6a009ed 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -20,6 +20,8 @@
 #include "add_efun.h"
 #include "peep.h"
 #include "lex.h"
+#include "program.h"
+#include "object.h"
 
 #define COMPARISON(ID,NAME,EXPR) \
 void ID(INT32 args) \
@@ -31,9 +33,7 @@ void ID(INT32 args) \
     error("Too few arguments to %s\n",NAME); \
   i=EXPR; \
   pop_n_elems(2); \
-  sp->type=T_INT; \
-  sp->u.integer=i; \
-  sp++; \
+  push_int(i); \
 }
 
 COMPARISON(f_eq,"`==", is_eq(sp-2,sp-1))
@@ -44,6 +44,17 @@ COMPARISON(f_gt,"`>" , is_gt(sp-2,sp-1))
 COMPARISON(f_ge,"`>=",!is_lt(sp-2,sp-1))
 
 
+#define CALL_OPERATOR(OP, args) \
+ if(!sp[-args].u.object->prog) \
+   error("Operator %s called in destructed object.\n",lfun_names[OP]); \
+ if(sp[-args].u.object->prog->lfuns[OP] == -1) \
+   error("No operator %s in object.\n",lfun_names[OP]); \
+ apply_lfun(sp[-args].u.object, OP, args-1); \
+ free_svalue(sp-2); \
+ sp[-2]=sp[-1]; \
+ sp--;
+
+
 void f_add(INT32 args)
 {
   INT32 e,size;
@@ -60,6 +71,9 @@ void f_add(INT32 args)
       switch(sp[-args].type)
       {
       case T_OBJECT:
+	CALL_OPERATOR(LFUN_ADD,args);
+	return;
+
       case T_PROGRAM:
       case T_FUNCTION:
 	error("Bad argument 1 to summation\n");
@@ -338,11 +352,17 @@ static int float_promote()
 
 void o_subtract()
 {
-  if (sp[-2].type != sp[-1].type && !float_promote())
+  if (sp[-2].type != sp[-1].type &&
+      !float_promote() &&
+      sp[-2].type != T_OBJECT)
     error("Subtract on different types.\n");
 
-  switch(sp[-1].type)
+  switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_SUBTRACT,2);
+    break;
+
   case T_ARRAY:
   {
     struct array *a;
@@ -431,11 +451,16 @@ static int generate_minus(node *n)
 
 void o_and()
 {
-  if(sp[-1].type != sp[-2].type)
+  if(sp[-1].type != sp[-2].type &&
+     sp[-2].type != T_OBJECT)
     error("Bitwise and on different types.\n");
 
   switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_AND,2);
+    break;
+
   case T_INT:
     sp--;
     sp[-1].u.integer &= sp[0].u.integer;
@@ -479,7 +504,13 @@ void f_and(INT32 args)
   case 0: error("Too few arguments to `&\n");
   case 1: return;
   case 2: o_and(); return;
-  default: while(--args > 0) o_and();
+  default:
+    if(sp[-args].type == T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_AND, args);
+    }else{
+      while(--args > 0) o_and();
+    }
   }
 }
 
@@ -503,11 +534,16 @@ static int generate_and(node *n)
 
 void o_or()
 {
-  if(sp[-1].type != sp[-2].type)
+  if(sp[-1].type != sp[-2].type &&
+     sp[-2].type != T_OBJECT)
     error("Bitwise or on different types.\n");
 
   switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_OR,2);
+    break;
+
   case T_INT:
     sp--;
     sp[-1].u.integer |= sp[0].u.integer;
@@ -552,7 +588,13 @@ void f_or(INT32 args)
   case 0: error("Too few arguments to `|\n");
   case 1: return;
   case 2: o_or(); return;
-  default: while(--args > 0) o_or();
+  default:
+    if(sp[-args].type==T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_OR, args);
+    } else {
+      while(--args > 0) o_or();
+    }
   }
 }
 
@@ -577,11 +619,16 @@ static int generate_or(node *n)
 
 void o_xor()
 {
-  if(sp[-1].type != sp[-2].type)
+  if(sp[-1].type != sp[-2].type &&
+     sp[-2].type != T_OBJECT)
     error("Bitwise xor on different types.\n");
 
   switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_XOR,2);
+    break;
+
   case T_INT:
     sp--;
     sp[-1].u.integer ^= sp[0].u.integer;
@@ -625,7 +672,13 @@ void f_xor(INT32 args)
   case 0: error("Too few arguments to `^\n");
   case 1: return;
   case 2: o_xor(); return;
-  default: while(--args > 0) o_xor();
+  default:
+    if(sp[-args].type==T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_XOR, args);
+    } else {
+      while(--args > 0) o_xor();
+    }
   }
 }
 
@@ -649,7 +702,16 @@ static int generate_xor(node *n)
 
 void o_lsh()
 {
-  if(sp[-2].type != T_INT) error("Bad argument 1 to <<\n");
+  if(sp[-2].type != T_INT)
+  {
+    if(sp[-2].type == T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_LSH,2);
+      return;
+    }
+
+    error("Bad argument 1 to <<\n");
+  }
   if(sp[-1].type != T_INT) error("Bad argument 2 to <<\n");
   sp--;
   sp[-1].u.integer = sp[-1].u.integer << sp->u.integer;
@@ -675,7 +737,15 @@ static int generate_lsh(node *n)
 
 void o_rsh()
 {
-  if(sp[-2].type != T_INT) error("Bad argument 1 to >>\n");
+  if(sp[-2].type != T_INT)
+  {
+    if(sp[-2].type == T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_RSH,2);
+      return;
+    }
+    error("Bad argument 1 to >>\n");
+  }
   if(sp[-1].type != T_INT) error("Bad argument 2 to >>\n");
   sp--;
   sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer;
@@ -740,6 +810,12 @@ void o_multiply()
     return;
 
   default:
+    if(sp[-2].type == T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_MULTIPLY,2);
+      return;
+    }
+
     error("Bad arguments to multiply.\n");
   }
 }
@@ -751,7 +827,13 @@ void f_multiply(INT32 args)
   case 0: error("Too few arguments to `*\n");
   case 1: return;
   case 2: o_multiply(); return;
-  default: while(--args > 0) o_multiply(); 
+  default:
+    if(sp[-args].type==T_OBJECT)
+    {
+      CALL_OPERATOR(LFUN_MULTIPLY, args);
+    } else {
+      while(--args > 0) o_multiply(); 
+    }
   }
 }
 
@@ -775,11 +857,17 @@ static int generate_multiply(node *n)
 
 void o_divide()
 {
-  if(sp[-2].type!=sp[-1].type && !float_promote())
+  if(sp[-2].type!=sp[-1].type &&
+     !float_promote() &&
+     sp[-2].type != T_OBJECT)
     error("Division on different types.\n");
 
   switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_DIVIDE,2);
+    break;
+
   case T_STRING:
   {
     struct array *ret;
@@ -831,11 +919,17 @@ static int generate_divide(node *n)
 
 void o_mod()
 {
-  if(sp[-2].type != sp[-1].type && !float_promote())
+  if(sp[-2].type != sp[-1].type &&
+     !float_promote() &&
+     sp[-2].type != T_OBJECT)
     error("Modulo on different types.\n");
 
-  switch(sp[-1].type)
+  switch(sp[-2].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_MOD,2);
+    break;
+
   case T_FLOAT:
   {
     FLOAT_TYPE foo;
@@ -878,14 +972,28 @@ static int generate_mod(node *n)
 
 void o_not()
 {
-  if(sp[-1].type==T_INT)
+  switch(sp[-1].type)
   {
+  case T_INT:
     sp[-1].u.integer = !sp[-1].u.integer;
-  }else{
-    pop_stack();
-    sp->type=T_INT;
-    sp->u.integer=0;
-    sp++;
+    break;
+
+  case T_FUNCTION:
+  case T_OBJECT:
+    if(IS_ZERO(sp-1))
+    {
+      pop_stack();
+      push_int(1);
+    }else{
+      pop_stack();
+      push_int(0);
+    }
+    break;
+
+  default:
+    free_svalue(sp-1);
+    sp[-1].type=T_INT;
+    sp[-1].u.integer=0;
   }
 }
 
@@ -910,6 +1018,10 @@ void o_compl()
 {
   switch(sp[-1].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_COMPL,1);
+    break;
+    
   case T_INT:
     sp[-1].u.integer = ~ sp[-1].u.integer;
     break;
@@ -944,6 +1056,10 @@ void o_negate()
 {
   switch(sp[-1].type)
   {
+  case T_OBJECT:
+    CALL_OPERATOR(LFUN_SUBTRACT,1);
+    break;
+
   case T_FLOAT:
     sp[-1].u.float_number=-sp[-1].u.float_number;
     return;
@@ -1016,30 +1132,37 @@ void init_operators()
 {
   add_efun2("`==",f_eq,"function(mixed,mixed:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
   add_efun2("`!=",f_ne,"function(mixed,mixed:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
-  add_efun2("`<", f_lt,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
-  add_efun2("`<=",f_le,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
-  add_efun2("`>", f_gt,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
-  add_efun2("`>=",f_ge,"function(int|float,int|float:int)|function(string,string:int)",OPT_TRY_OPTIMIZE,0,generate_comparison);
+  add_efun2("`!",f_not,"function(mixed:int)",OPT_TRY_OPTIMIZE,0,generate_not);
 
-  add_efun2("`+",f_add,"function(int...:int)|!function(int...:mixed)&function(int|float...:float)|!function(int|float...:mixed)&function(string|int|float...:string)|function(array...:array)|function(mapping...:mapping)|function(list...:list)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum);
+#define CMP_TYPE "function(object,mixed:int)|function(mixed,object:int)|function(int|float,int|float:int)|function(string,string:int)"
+  add_efun2("`<", f_lt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison);
+  add_efun2("`<=",f_le,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison);
+  add_efun2("`>", f_gt,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison);
+  add_efun2("`>=",f_ge,CMP_TYPE,OPT_TRY_OPTIMIZE,0,generate_comparison);
 
-  add_efun2("`-",f_minus,"function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",OPT_TRY_OPTIMIZE,0,generate_minus);
+  add_efun2("`+",f_add,"function(object,mixed...:mixed)|function(int...:int)|!function(int...:mixed)&function(int|float...:float)|!function(int|float...:mixed)&function(string|int|float...:string)|function(array...:array)|function(mapping...:mapping)|function(list...:list)",OPT_TRY_OPTIMIZE,optimize_binary,generate_sum);
 
-  add_efun2("`&",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_and);
+  add_efun2("`-",f_minus,"function(object,mixed...:mixed)|function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float|int,float:float)|function(float,int:float)|function(int,int:int)|function(string,string:string)",OPT_TRY_OPTIMIZE,0,generate_minus);
 
-  add_efun2("`|",f_or,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_or);
+#define LOG_TYPE "function(object,mixed...:mixed)|function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)"
 
-  add_efun2("`^",f_xor,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",OPT_TRY_OPTIMIZE,optimize_binary,generate_xor);
+  add_efun2("`&",f_and,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_and);
 
-  add_efun2("`<<",f_lsh,"function(int,int:int)",OPT_TRY_OPTIMIZE,0,generate_lsh);
-  add_efun2("`>>",f_rsh,"function(int,int:int)",OPT_TRY_OPTIMIZE,0,generate_rsh);
+  add_efun2("`|",f_or,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_or);
 
-  add_efun2("`*",f_multiply,"function(int...:int)|!function(int...:mixed)&function(float|int...:float)|function(string*,string:string)",OPT_TRY_OPTIMIZE,optimize_binary,generate_multiply);
+  add_efun2("`^",f_xor,LOG_TYPE,OPT_TRY_OPTIMIZE,optimize_binary,generate_xor);
 
-  add_efun2("`/",f_divide,"function(int,int:int)|function(float|int,float:float)|function(float,int:float)|function(string,string:string*)",OPT_TRY_OPTIMIZE,0,generate_divide);
 
-  add_efun2("`%",f_mod,"function(int,int:int)|!function(int,int:mixed)&function(int|float,int|float:float)",OPT_TRY_OPTIMIZE,0,generate_mod);
+#define SHIFT_TYPE "function(object,mixed:mixed)|function(int,int:int)"
 
-  add_efun2("`!",f_not,"function(mixed:int)",OPT_TRY_OPTIMIZE,0,generate_not);
-  add_efun2("`~",f_compl,"function(int:int)|function(float:float)",OPT_TRY_OPTIMIZE,0,generate_compl);
+  add_efun2("`<<",f_lsh,SHIFT_TYPE,OPT_TRY_OPTIMIZE,0,generate_lsh);
+  add_efun2("`>>",f_rsh,SHIFT_TYPE,OPT_TRY_OPTIMIZE,0,generate_rsh);
+
+  add_efun2("`*",f_multiply,"function(object,mixed...:mixed)|function(int...:int)|!function(int...:mixed)&function(float|int...:float)|function(string*,string:string)",OPT_TRY_OPTIMIZE,optimize_binary,generate_multiply);
+
+  add_efun2("`/",f_divide,"function(object,mixed:mixed)|function(int,int:int)|function(float|int,float:float)|function(float,int:float)|function(string,string:string*)",OPT_TRY_OPTIMIZE,0,generate_divide);
+
+  add_efun2("`%",f_mod,"function(object,mixed:mixed)|function(int,int:int)|!function(int,int:mixed)&function(int|float,int|float:float)",OPT_TRY_OPTIMIZE,0,generate_mod);
+
+  add_efun2("`~",f_compl,"function(object:mixed)|function(int:int)|function(float:float)",OPT_TRY_OPTIMIZE,0,generate_compl);
 }
diff --git a/src/svalue.c b/src/svalue.c
index 300745e4c93a7d303b678e928235e0d2d14e041a..aa14b70353ed5f8a8c0b822cb511c38f4af48b95 100644
--- a/src/svalue.c
+++ b/src/svalue.c
@@ -15,6 +15,7 @@
 #include "add_efun.h"
 #include "error.h"
 #include "dynamic_buffer.h"
+#include "interpret.h"
 
 /*
  * This routine frees a short svalue given a pointer to it and
@@ -330,6 +331,86 @@ void assign_short_svalue(union anything *to,
   }
 }
 
+unsigned INT32 hash_svalue(struct svalue *s)
+{
+  unsigned INT32 q;
+
+  check_type(s->type);
+  check_refs(s);
+
+  switch(s->type)
+  {
+  case T_OBJECT:
+    if(!s->u.object->prog)
+    {
+      q=0;
+      break;
+    }
+
+    if(s->u.object->prog->lfuns[LFUN___HASH] != -1)
+    {
+      safe_apply_low(s->u.object, s->u.object->prog->lfuns[LFUN___HASH], 0);
+      if(sp[-1].type == T_INT)
+      {
+	q=sp[-1].u.integer;
+      }else{
+	q=0;
+      }
+      pop_stack();
+      break;
+    }
+
+  default:      q=(unsigned INT32)s->u.refs >> 2;
+  case T_INT:   q=s->u.integer; break;
+  case T_FLOAT: q=(unsigned INT32)(s->u.float_number * 16843009.0); break;
+  }
+  q+=q % 997;
+  q+=((q + s->type) * 9248339);
+  
+  return q;
+}
+
+int svalue_is_true(struct svalue *s)
+{
+  unsigned INT32 q;
+  check_type(s->type);
+  check_refs(s);
+
+  switch(s->type)
+  {
+  case T_INT:
+    if(s->u.integer) return 1;
+    return 0;
+
+  case T_FUNCTION:
+    check_destructed(s);
+    if(sp[-1].type==T_INT) return 0;
+    return 1;
+
+  case T_OBJECT:
+    check_destructed(s);
+    if(sp[-1].type==T_INT) return 0;
+    if(!s->u.object->prog) return 0;
+
+    if(s->u.object->prog->lfuns[LFUN_NOT]!=-1)
+    {
+      safe_apply_low(s->u.object,s->u.object->prog->lfuns[LFUN_NOT],0);
+      if(sp[-1].type == T_INT && sp[-1].u.integer == 0)
+      {
+	pop_stack();
+	return 1;
+      } else {
+	return 0;
+      }
+    }
+
+  default:
+    return 1;
+  }
+    
+}
+
+
 int is_eq(struct svalue *a, struct svalue *b)
 {
   check_type(a->type);
@@ -340,11 +421,58 @@ int is_eq(struct svalue *a, struct svalue *b)
   check_destructed(a);
   check_destructed(b);
 
-  if (a->type != b->type) return 0;
+  if (a->type != b->type)
+  {
+    if(a->type == T_OBJECT)
+    {
+      if(a->u.object->prog->lfuns[LFUN_EQ] != -1)
+      {
+      a_is_obj:
+	assign_svalue_no_free(sp, b);
+	sp++;
+	apply_lfun(a->u.object, LFUN_EQ, 1);
+	if(IS_ZERO(sp-1))
+	{
+	  pop_stack();
+	  return 0;
+	}else{
+	  pop_stack();
+	  return 1;
+	}
+      }
+    }
+
+    if(b->type == T_OBJECT)
+    {
+      if(b->u.object->prog->lfuns[LFUN_EQ] != -1)
+      {
+      b_is_obj:
+	assign_svalue_no_free(sp, a);
+	sp++;
+	apply_lfun(b->u.object, LFUN_EQ, 1);
+	if(IS_ZERO(sp-1))
+	{
+	  pop_stack();
+	  return 0;
+	}else{
+	  pop_stack();
+	  return 1;
+	}
+      }
+    }
+
+    return 0;
+  }
   switch(a->type)
   {
-  case T_LIST:
   case T_OBJECT:
+    if(a->u.object->prog->lfuns[LFUN_EQ] != -1)
+      goto a_is_obj;
+
+    if(b->u.object->prog->lfuns[LFUN_EQ] != -1)
+      goto b_is_obj;
+
+  case T_LIST:
   case T_PROGRAM:
   case T_ARRAY:
   case T_MAPPING:
@@ -444,7 +572,7 @@ int is_equal(struct svalue *a,struct svalue *b)
   return low_is_equal(a,b,0);
 }
 
-int is_lt(const struct svalue *a,const struct svalue *b)
+int is_lt(struct svalue *a,struct svalue *b)
 {
   check_type(a->type);
   check_type(b->type);
@@ -459,10 +587,52 @@ int is_lt(const struct svalue *a,const struct svalue *b)
     if(a->type == T_INT && b->type==T_FLOAT)
       return (FLOAT_TYPE)a->u.integer < b->u.float_number;
 
+    if(a->type == T_OBJECT)
+    {
+    a_is_object:
+      if(!a->u.object->prog)
+	error("Comparison on destructed object.\n");
+      if(a->u.object->prog->lfuns[LFUN_LT] == -1)
+	error("Object lacks '<\n");
+      assign_svalue_no_free(sp, b);
+      sp++;
+      apply_lfun(a->u.object, LFUN_LT, 1);
+      if(IS_ZERO(sp-1))
+      {
+	pop_stack();
+	return 0;
+      }else{
+	pop_stack();
+	return 1;
+      }
+    }
+
+    if(b->type == T_OBJECT)
+    {
+      if(!b->u.object->prog)
+	error("Comparison on destructed object.\n");
+      if(b->u.object->prog->lfuns[LFUN_GT] == -1)
+	error("Object lacks '>\n");
+      assign_svalue_no_free(sp, a);
+      sp++;
+      apply_lfun(b->u.object, LFUN_GT, 1);
+      if(IS_ZERO(sp-1))
+      {
+	pop_stack();
+	return 0;
+      }else{
+	pop_stack();
+	return 1;
+      }
+    }
+    
     error("Cannot compare different types.\n");
   }
   switch(a->type)
   {
+  case T_OBJECT:
+    goto a_is_object;
+
   default:
     error("Bad type to comparison.\n");
 
diff --git a/src/svalue.h b/src/svalue.h
index 29c3e9b7efac0b1186b1a61610030b4a8183157f..4426fcc3eb7f966e6eaa4dced1cb8df55831075d 100644
--- a/src/svalue.h
+++ b/src/svalue.h
@@ -95,7 +95,7 @@ struct svalue
 #define NUMBER_DESTRUCTED 2
 
 #define is_gt(a,b) is_lt(b,a)
-#define IS_ZERO(X) ((X)->type==T_INT && (X)->u.integer==0)
+#define IS_ZERO(X) ((X)->type==T_INT?(X)->u.integer==0:(1<<(X)->type)&(BIT_OBJECT|BIT_FUNCTION)?!svalue_is_true(X):0)
 
 #define check_destructed(S) \
 do{ \
@@ -162,6 +162,8 @@ void assign_short_svalue_no_free(union anything *to,
 void assign_short_svalue(union anything *to,
 			 union anything *from,
 			 TYPE_T type);
+unsigned INT32 hash_svalue(struct svalue *s);
+int svalue_is_true(struct svalue *s);
 int is_eq(struct svalue *a, struct svalue *b);
 int low_is_equal(struct svalue *a,
 		 struct svalue *b,
@@ -171,7 +173,7 @@ int low_short_is_equal(const union anything *a,
 		       TYPE_T type,
 		       struct processing *p);
 int is_equal(struct svalue *a,struct svalue *b);
-int is_lt(const struct svalue *a,const struct svalue *b);
+int is_lt(struct svalue *a,struct svalue *b);
 void describe_svalue(struct svalue *s,int indent,struct processing *p);
 void clear_svalues(struct svalue *s, INT32 num);
 void copy_svalues_recursively_no_free(struct svalue *to,