diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v
index aefc4b360b..a829a547e9 100644
--- a/vlib/v/ast/ast.v
+++ b/vlib/v/ast/ast.v
@@ -157,6 +157,7 @@ pub struct InterfaceDecl {
 pub:
 	name        string
 	field_names []string
+	methods     []FnDecl
 }
 
 pub struct StructInitField {
@@ -541,7 +542,6 @@ pub:
 	name   string
 	is_pub bool
 	fields []EnumField
-	// default_exprs []Expr
 	pos    token.Position
 }
 
@@ -739,22 +739,46 @@ pub fn expr_is_call(expr Expr) bool {
 
 fn (expr Expr) position() token.Position {
 	// all uncommented have to be implemented
-	match var expr {
-		ArrayInit { return it.pos }
-		AsCast { return it.pos }
+	match mut expr {
+		ArrayInit {
+			return it.pos
+		}
+		AsCast {
+			return it.pos
+		}
 		// ast.Ident { }
-		AssignExpr { return it.pos }
+		AssignExpr {
+			return it.pos
+		}
 		// ast.CastExpr { }
-		Assoc { return it.pos }
-		BoolLiteral { return it.pos }
-		CallExpr { return it.pos }
-		CharLiteral { return it.pos }
-		EnumVal { return it.pos }
-		FloatLiteral { return it.pos }
-		Ident { return it.pos }
-		IfExpr { return it.pos }
+		Assoc {
+			return it.pos
+		}
+		BoolLiteral {
+			return it.pos
+		}
+		CallExpr {
+			return it.pos
+		}
+		CharLiteral {
+			return it.pos
+		}
+		EnumVal {
+			return it.pos
+		}
+		FloatLiteral {
+			return it.pos
+		}
+		Ident {
+			return it.pos
+		}
+		IfExpr {
+			return it.pos
+		}
 		// ast.IfGuardExpr { }
-		IndexExpr { return it.pos }
+		IndexExpr {
+			return it.pos
+		}
 		InfixExpr {
 			left_pos := it.left.position()
 			right_pos := it.right.position()
@@ -767,20 +791,40 @@ fn (expr Expr) position() token.Position {
 				len: right_pos.pos - left_pos.pos + right_pos.len
 			}
 		}
-		IntegerLiteral { return it.pos }
-		MapInit { return it.pos }
-		MatchExpr { return it.pos }
-		PostfixExpr { return it.pos }
+		IntegerLiteral {
+			return it.pos
+		}
+		MapInit {
+			return it.pos
+		}
+		MatchExpr {
+			return it.pos
+		}
+		PostfixExpr {
+			return it.pos
+		}
 		// ast.None { }
-		PrefixExpr { return it.pos }
+		PrefixExpr {
+			return it.pos
+		}
 		// ast.ParExpr { }
-		SelectorExpr { return it.pos }
+		SelectorExpr {
+			return it.pos
+		}
 		// ast.SizeOf { }
-		StringLiteral { return it.pos }
-		StringInterLiteral { return it.pos }
+		StringLiteral {
+			return it.pos
+		}
+		StringInterLiteral {
+			return it.pos
+		}
 		// ast.Type { }
-		StructInit { return it.pos }
+		StructInit {
+			return it.pos
+		}
 		// ast.TypeOf { }
-		else { return token.Position{} }
+		else {
+			return token.Position{}
+		}
 	}
 }
diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v
index cf1069f394..e95be6a00d 100644
--- a/vlib/v/checker/checker.v
+++ b/vlib/v/checker/checker.v
@@ -471,13 +471,13 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
 			//println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
 			c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
 		}
-		no_args := method.args.len - 1
+		nr_args := if method.args.len == 0 {  0 } else {method.args.len - 1}
 		min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
 		if call_expr.args.len < min_required_args {
 			c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)',
 				call_expr.pos)
-		} else if !method.is_variadic && call_expr.args.len > no_args {
-			c.error('too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $no_args)',
+		} else if !method.is_variadic && call_expr.args.len > nr_args {
+			c.error('!too many arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $nr_args)',
 				call_expr.pos)
 			return method.return_type
 		}
@@ -530,7 +530,7 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
 			return info.func.return_type
 		}
 	}
-	c.error('unknown method: ${left_type_sym.name}.$method_name', call_expr.pos)
+	c.error('unknown method: `${left_type_sym.name}.$method_name`', call_expr.pos)
 	return table.void_type
 }
 
diff --git a/vlib/v/checker/tests/inout/unknown_method.out b/vlib/v/checker/tests/inout/unknown_method.out
index ad5f480fa5..fc09c377fc 100644
--- a/vlib/v/checker/tests/inout/unknown_method.out
+++ b/vlib/v/checker/tests/inout/unknown_method.out
@@ -1,4 +1,4 @@
-vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: Test.sdd
+vlib/v/checker/tests/inout/unknown_method.v:7:12: error: unknown method: `Test.sdd`
     5| fn main() {
     6|     t := Test{}
     7|     println(t.sdd())
diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v
index fabb8bda52..aed8d56553 100644
--- a/vlib/v/fmt/fmt.v
+++ b/vlib/v/fmt/fmt.v
@@ -333,6 +333,14 @@ fn (mut f Fmt) stmt(node ast.Stmt) {
 			// Imports are handled after the file is formatted, to automatically add necessary modules
 			// f.imports(f.file.imports)
 		}
+		ast.InterfaceDecl {
+			f.writeln('interface $it.name {')
+			for method in it.methods {
+				f.write('\t')
+				f.writeln(method.str(f.table).after('fn '))
+			}
+			f.writeln('}\n')
+		}
 		ast.Module {
 			f.mod(it)
 		}
diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v
index 1c35b3966e..f8dcf5f230 100644
--- a/vlib/v/gen/cgen.v
+++ b/vlib/v/gen/cgen.v
@@ -151,17 +151,11 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
 	}
 	//
 	g.finish()
-	return g.hashes() +
-		'\n// V typedefs:\n' + g.typedefs.str() +
-		'\n// V typedefs2:\n' + g.typedefs2.str() +
-		'\n// V cheaders:\n' + g.cheaders.str() +
-		'\n// V includes:\n' + g.includes.str() +
-		'\n// V definitions:\n' + g.definitions.str() +
-		'\n// V gowrappers:\n' + g.gowrappers.str() +
-		'\n// V stringliterals:\n' + g.stringliterals.str() +
-		'\n// V auto str functions:\n' + g.auto_str_funcs.str() +
-		'\n// V out\n' + g.out.str() +
-		'\n// THE END.'
+	return g.hashes() + '\n// V typedefs:\n' + g.typedefs.str() + '\n// V typedefs2:\n' + g.typedefs2.str() +
+		'\n// V cheaders:\n' + g.cheaders.str() + '\n// V includes:\n' + g.includes.str() + '\n// V definitions:\n' +
+		g.definitions.str() + g.interface_table() + '\n// V gowrappers:\n' + g.gowrappers.str() + '\n// V stringliterals:\n' +
+		g.stringliterals.str() + '\n// V auto str functions:\n' + g.auto_str_funcs.str() + '\n// V out\n' +
+		g.out.str() + '\n// THE END.'
 }
 
 pub fn (g Gen) hashes() string {
@@ -400,10 +394,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 	match node {
 		ast.InterfaceDecl {
 			g.writeln('//interface')
-			g.writeln('struct $it.name {')
+			g.writeln('typedef struct {')
 			g.writeln('\tvoid* _object;')
 			g.writeln('\tint _interface_idx;')
-			g.writeln('};')
+			g.writeln('} $it.name;')
 		}
 		ast.AssertStmt {
 			g.gen_assert_stmt(it)
@@ -458,11 +452,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
 					cur_enum_expr = expr_str
 					cur_enum_offset = 0
 				}
-				cur_value := if cur_enum_offset > 0 {
-				   '${cur_enum_expr}+${cur_enum_offset}'
-				} else {
-				   cur_enum_expr
-				}
+				cur_value := if cur_enum_offset > 0 { '${cur_enum_expr}+${cur_enum_offset}' } else { cur_enum_expr }
 				g.typedefs.writeln(', // ${cur_value}')
 				cur_enum_offset++
 			}
@@ -2221,6 +2211,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
 	}
 	// loop over types
 	for t in typesa {
+		if t.kind == .interface_ {
+			continue
+		}
 		// create list of deps
 		mut field_deps := []string
 		match t.info {
@@ -2232,6 +2225,9 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
 			}
 			table.Struct {
 				info := t.info as table.Struct
+				// if info.is_interface {
+				// continue
+				// }
 				for field in info.fields {
 					dep := g.table.get_type_symbol(field.typ).name
 					// skip if not in types list or already in deps
@@ -2297,15 +2293,15 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
 		} else if sym.kind in [.struct_, .map] && !sym.has_method('str') {
 			g.write('%.*s')
 		} else if node.expr_types[i] == table.i16_type {
-		        g.write('%"PRId16"')
+			g.write('%"PRId16"')
 		} else if node.expr_types[i] == table.u16_type {
-		        g.write('%"PRIu16"')
+			g.write('%"PRIu16"')
 		} else if node.expr_types[i] == table.u32_type {
-		        g.write('%"PRIu32"')
+			g.write('%"PRIu32"')
 		} else if node.expr_types[i] == table.i64_type {
-		        g.write('%"PRId64"')
+			g.write('%"PRId64"')
 		} else if node.expr_types[i] == table.u64_type {
-		        g.write('%"PRIu64"')
+			g.write('%"PRIu64"')
 		} else {
 			g.write('%"PRId32"')
 		}
@@ -2849,14 +2845,14 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
 }
 
 fn styp_to_str_fn_name(styp string) string {
-	res := styp.replace('.', '__').replace('*','_ptr') + '_str'
+	res := styp.replace('.', '__').replace('*', '_ptr') + '_str'
 	return res
 }
 
 // already generated styp, reuse it
-fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp, str_fn_name string) {
 	already_generated_key := '${styp}:${str_fn_name}'
-	if sym.has_method('str') ||  already_generated_key in g.str_types {
+	if sym.has_method('str') || already_generated_key in g.str_types {
 		return
 	}
 	g.str_types << already_generated_key
@@ -2870,7 +2866,7 @@ fn (mut g Gen) gen_str_for_type(sym table.TypeSymbol, styp string, str_fn_name s
 	}
 }
 
-fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp, str_fn_name string) {
 	mut convertor := ''
 	mut typename := ''
 	if sym.parent_idx in table.integer_type_idxs {
@@ -2901,7 +2897,7 @@ fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name st
 	g.auto_str_funcs.writeln('}')
 }
 
-fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_for_enum(info table.Enum, styp, str_fn_name string) {
 	s := styp.replace('.', '__')
 	g.definitions.writeln('string ${str_fn_name}($styp it); // auto')
 	g.auto_str_funcs.writeln('string ${str_fn_name}($styp it) { /* gen_str_for_enum */')
@@ -2914,27 +2910,29 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string, str_fn_name string
 	g.auto_str_funcs.writeln('}')
 }
 
-fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_for_struct(info table.Struct, styp, str_fn_name string) {
 	// TODO: short it if possible
 	// generates all definitions of substructs
-	mut fnames2strfunc := map[string]string
+	mut fnames2strfunc := {
+		'': ''
+	} // map[string]string // TODO vfmt bug
 	for i, field in info.fields {
 		sym := g.table.get_type_symbol(field.typ)
 		if sym.kind in [.struct_, .array, .array_fixed, .map, .enum_] {
 			field_styp := g.typ(field.typ)
-			field_fn_name := styp_to_str_fn_name( field_styp )
-			fnames2strfunc[ field_styp ] = field_fn_name
+			field_fn_name := styp_to_str_fn_name(field_styp)
+			fnames2strfunc[field_styp] = field_fn_name
 			g.gen_str_for_type(sym, field_styp, field_fn_name)
 		}
 	}
 	g.definitions.writeln('string ${str_fn_name}($styp x, int indent_count); // auto')
 	g.auto_str_funcs.writeln('string ${str_fn_name}($styp x, int indent_count) {')
-	mut clean_struct_v_type_name := styp.replace('__','.')
+	mut clean_struct_v_type_name := styp.replace('__', '.')
 	if styp.ends_with('*') {
 		deref_typ := styp.replace('*', '')
 		g.auto_str_funcs.writeln('\t${deref_typ} *it = x;')
 		clean_struct_v_type_name = '&' + clean_struct_v_type_name.replace('*', '')
-	}else{
+	} else {
 		deref_typ := styp
 		g.auto_str_funcs.writeln('\t${deref_typ} *it = &x;')
 	}
@@ -2954,14 +2952,14 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
 		for i, field in info.fields {
 			sym := g.table.get_type_symbol(field.typ)
 			has_custom_str := sym.has_method('str')
-			second_str_param := if has_custom_str {''} else {', indent_count + 1'}
+			second_str_param := if has_custom_str { '' } else { ', indent_count + 1' }
 			field_styp := g.typ(field.typ)
-			field_styp_fn_name := if has_custom_str {'${field_styp}_str'} else {fnames2strfunc[ field_styp ]}
-			if sym.kind  == .enum_ {
+			field_styp_fn_name := if has_custom_str { '${field_styp}_str' } else { fnames2strfunc[field_styp] }
+			if sym.kind == .enum_ {
 				g.auto_str_funcs.write('indents.len, indents.str, ')
 				g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).len, ')
 				g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name} ).str  ')
-			}else if sym.kind in [.struct_, .array, .array_fixed] {
+			} else if sym.kind in [.struct_, .array, .array_fixed] {
 				g.auto_str_funcs.write('indents.len, indents.str, ')
 				g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).len, ')
 				g.auto_str_funcs.write('${field_styp_fn_name}( it->${field.name}${second_str_param} ).str  ')
@@ -2983,11 +2981,11 @@ fn (mut g Gen) gen_str_for_struct(info table.Struct, styp string, str_fn_name st
 	g.auto_str_funcs.writeln('}')
 }
 
-fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_for_array(info table.Array, styp, str_fn_name string) {
 	sym := g.table.get_type_symbol(info.elem_type)
 	field_styp := g.typ(info.elem_type)
 	if sym.kind == .struct_ && !sym.has_method('str') {
-		g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp) )
+		g.gen_str_for_type(sym, field_styp, styp_to_str_fn_name(field_styp))
 	}
 	g.definitions.writeln('string ${str_fn_name}($styp a); // auto')
 	g.auto_str_funcs.writeln('string ${str_fn_name}($styp a) {')
@@ -3011,7 +3009,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
 	g.auto_str_funcs.writeln('}')
 }
 
-fn (mut g Gen) gen_str_for_map(info table.Map, styp string, str_fn_name string) {
+fn (mut g Gen) gen_str_for_map(info table.Map, styp, str_fn_name string) {
 	key_sym := g.table.get_type_symbol(info.key_type)
 	key_styp := g.typ(info.key_type)
 	if key_sym.kind == .struct_ && !key_sym.has_method('str') {
@@ -3068,3 +3066,60 @@ fn (g Gen) type_to_fmt(typ table.Type) string {
 	}
 	return '%d'
 }
+
+// Generates interface table and interface indexes
+fn (v &Gen) interface_table() string {
+	mut sb := strings.new_builder(100)
+	for _, t in v.table.types {
+		if t.kind != .interface_ {
+			continue
+		}
+		info := t.info as table.Interface
+		// interface_name is for example Speaker
+		interface_name := t.name
+		mut methods := ''
+		mut generated_casting_functions := ''
+		sb.writeln('// NR gen_types= $info.gen_types.len')
+		for i, gen_type in info.gen_types {
+			// ptr_ctype can be for example Cat OR Cat_ptr:
+			ptr_ctype := gen_type.replace('*', '_ptr')
+			// cctype is the Cleaned Concrete Type name, *without ptr*,
+			// i.e. cctype is always just Cat, not Cat_ptr:
+			cctype := gen_type.replace('*', '')
+			// Speaker_Cat_index = 0
+			interface_index_name := '_${interface_name}_${ptr_ctype}_index'
+			generated_casting_functions += '
+${interface_name} I_${cctype}_to_${interface_name}(${cctype} x) {
+  return (${interface_name}){
+           ._object = (void*) memdup(&x, sizeof(${cctype})),
+           ._interface_idx = ${interface_index_name} };
+}
+'
+			methods += '{\n'
+			for j, method in t.methods {
+				// Cat_speak
+				methods += ' (void*)    ${cctype}_${method.name}'
+				if j < t.methods.len - 1 {
+					methods += ', \n'
+				}
+			}
+			methods += '\n},\n\n'
+			sb.writeln('int ${interface_index_name} = $i;')
+		}
+		if info.gen_types.len > 0 {
+			// methods = '{TCCSKIP(0)}'
+			// }
+			sb.writeln('void* (* ${interface_name}_name_table[][$t.methods.len]) = ' + '{ \n $methods \n }; ')
+		} else {
+			// The line below is needed so that C compilation succeeds,
+			// even if no interface methods are called.
+			// See https://github.com/zenith391/vgtk3/issues/7
+			sb.writeln('void* (* ${interface_name}_name_table[][1]) = ' + '{ {NULL} }; ')
+		}
+		if generated_casting_functions.len > 0 {
+			sb.writeln('// Casting functions for interface "${interface_name}" :')
+			sb.writeln(generated_casting_functions)
+		}
+	}
+	return sb.str()
+}
diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v
index 78d3316cc6..793ac7eb86 100644
--- a/vlib/v/gen/fn.v
+++ b/vlib/v/gen/fn.v
@@ -3,13 +3,11 @@
 // that can be found in the LICENSE file.
 module gen
 
-import (
-	v.ast
-	v.table
-	v.util
-)
+import v.ast
+import v.table
+import v.util
 
-fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
+fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
 	if it.is_c {
 		// || it.no_body {
 		return
@@ -88,7 +86,6 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
 			g.writeln('\tint ___argc;')
 			g.writeln('\twchar_t** ___argv = CommandLineToArgvW(cmd_line, &___argc);')
 		}
-
 		g.writeln('\t_vinit();')
 		if g.is_importing_os() {
 			if g.autofree {
@@ -126,11 +123,11 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
 	g.fn_decl = 0
 }
 
-fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) {
+fn (mut g Gen) fn_args(args []table.Arg, is_variadic bool) {
 	no_names := args.len > 0 && args[0].name == 'arg_1'
 	for i, arg in args {
 		arg_type_sym := g.table.get_type_symbol(arg.typ)
-		mut arg_type_name := g.typ(arg.typ)		// arg_type_sym.name.replace('.', '__')
+		mut arg_type_name := g.typ(arg.typ) // arg_type_sym.name.replace('.', '__')
 		is_varg := i == args.len - 1 && is_variadic
 		if is_varg {
 			varg_type_str := int(arg.typ).str()
@@ -175,7 +172,7 @@ fn (g mut Gen) fn_args(args []table.Arg, is_variadic bool) {
 	}
 }
 
-fn (g mut Gen) call_expr(node ast.CallExpr) {
+fn (mut g Gen) call_expr(node ast.CallExpr) {
 	gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
 	tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
 	if gen_or {
@@ -192,21 +189,37 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
 	}
 }
 
-fn (g mut Gen) method_call(node ast.CallExpr) {
+fn (mut g Gen) method_call(node ast.CallExpr) {
 	// TODO: there are still due to unchecked exprs (opt/some fn arg)
 	if node.left_type == 0 {
 		verror('method receiver type is 0, this means there are some uchecked exprs')
 	}
 	typ_sym := g.table.get_type_symbol(node.receiver_type)
-	// rec_sym := g.table.get_type_symbol(node.receiver_type)
 	mut receiver_name := typ_sym.name
+	if typ_sym.kind == .interface_ {
+		g.writeln('// interface method call')
+		// `((void (*)())(Speaker_name_table[s._interface_idx][1]))(s._object);`
+		g.write('((void (*)())(${receiver_name}_name_table[')
+		g.expr(node.left)
+		g.write('._interface_idx][1]))(')
+		g.expr(node.left)
+		g.writeln('._object );')
+		return
+	}
+	// rec_sym := g.table.get_type_symbol(node.receiver_type)
 	if typ_sym.kind == .array && node.name == 'filter' {
 		g.gen_filter(node)
 		return
 	}
 	// TODO performance, detect `array` method differently
 	if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
-		'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
+		'trim'
+	'first'
+	'last'
+	'clone'
+	'reverse'
+	'slice'
+	] {
 		// && rec_sym.name == 'array' {
 		// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
 		// `array_byte_clone` => `array_clone`
@@ -255,7 +268,7 @@ fn (g mut Gen) method_call(node ast.CallExpr) {
 	// }
 }
 
-fn (g mut Gen) fn_call(node ast.CallExpr) {
+fn (mut g Gen) fn_call(node ast.CallExpr) {
 	// call struct field with fn type
 	// TODO: test node.left instead
 	// left & left_type will be `x` and `x type` in `x.fieldfn()`
@@ -264,8 +277,7 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
 		g.expr(node.left)
 		if table.type_is_ptr(node.left_type) {
 			g.write('->')
-		}
-		else {
+		} else {
 			g.write('.')
 		}
 	}
@@ -322,15 +334,9 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
 		} else {
 			expr := node.args[0].expr
 			is_var := match expr {
-				ast.SelectorExpr {
-					true
-				}
-				ast.Ident {
-					true
-				}
-				else {
-					false
-				}
+				ast.SelectorExpr { true }
+				ast.Ident { true }
+				else { false }
 			}
 			if table.type_is_ptr(typ) && sym.kind != .struct_ {
 				// ptr_str() for pointers
@@ -361,7 +367,7 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
 				}
 				g.expr(expr)
 				if sym.kind == .struct_ && styp != 'ptr' && !sym.has_method('str') {
-					g.write(', 0')					// trailing 0 is initial struct indent count
+					g.write(', 0') // trailing 0 is initial struct indent count
 				}
 			}
 			g.write('))')
@@ -381,10 +387,10 @@ fn (g mut Gen) fn_call(node ast.CallExpr) {
 	}
 }
 
-fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
+fn (mut g Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
 	is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
 		1], .variadic)
-	is_forwarding_varg := args.len > 0 && table.type_is(args[args.len-1].typ, .variadic)
+	is_forwarding_varg := args.len > 0 && table.type_is(args[args.len - 1].typ, .variadic)
 	gen_vargs := is_variadic && !is_forwarding_varg
 	mut arg_no := 0
 	for arg in args {
@@ -427,7 +433,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
 }
 
 [inline]
-fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
+fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
 	arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
 	expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
 	if arg.is_mut && !arg_is_ptr {
@@ -454,7 +460,7 @@ fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
 	g.expr_with_cast(arg.expr, arg.typ, expected_type)
 }
 
-fn (g mut Gen) is_gui_app() bool {
+fn (mut g Gen) is_gui_app() bool {
 	$if windows {
 		for cf in g.table.cflags {
 			if cf.value == 'gdi32' {
diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v
index 1b9efaea23..0e8cedef33 100644
--- a/vlib/v/parser/struct.v
+++ b/vlib/v/parser/struct.v
@@ -7,7 +7,7 @@ import v.ast
 import v.table
 import v.token
 
-fn (var p Parser) struct_decl() ast.StructDecl {
+fn (mut p Parser) struct_decl() ast.StructDecl {
 	start_pos := p.tok.position()
 	is_pub := p.tok.kind == .key_pub
 	if is_pub {
@@ -22,8 +22,8 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 	is_c := p.tok.lit == 'C' && p.peek_tok.kind == .dot
 	is_js := p.tok.lit == 'JS' && p.peek_tok.kind == .dot
 	if is_c {
-		p.next()		// C || JS
-		p.next()		// .
+		p.next() // C || JS
+		p.next() // .
 	}
 	is_typedef := p.attr == 'typedef'
 	no_body := p.peek_tok.kind != .lcbr
@@ -31,17 +31,17 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 		p.error('`$p.tok.lit` lacks body')
 	}
 	end_pos := p.tok.position()
-	var name := p.check_name()
+	mut name := p.check_name()
 	// println('struct decl $name')
-	var ast_fields := []ast.StructField
-	var fields := []table.Field
-	var mut_pos := -1
-	var pub_pos := -1
-	var pub_mut_pos := -1
+	mut ast_fields := []ast.StructField
+	mut fields := []table.Field
+	mut mut_pos := -1
+	mut pub_pos := -1
+	mut pub_mut_pos := -1
 	if !no_body {
 		p.check(.lcbr)
 		for p.tok.kind != .rcbr {
-			var comment := ast.Comment{}
+			mut comment := ast.Comment{}
 			if p.tok.kind == .comment {
 				comment = p.comment()
 			}
@@ -72,8 +72,8 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 			println('XXXX' + s.str())
 		}
 */
-			var default_expr := ast.Expr{}
-			var has_default_expr := false
+			mut default_expr := ast.Expr{}
+			mut has_default_expr := false
 			if p.tok.kind == .assign {
 				// Default value
 				p.next()
@@ -81,15 +81,13 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 				// p.expr(0)
 				default_expr = p.expr(0)
 				match default_expr {
-					ast.EnumVal {
-						it.typ = typ
-					}
+					ast.EnumVal { it.typ = typ }
 					// TODO: implement all types??
 					else {}
 				}
 				has_default_expr = true
 			}
-			var attr := ast.Attr{}
+			mut attr := ast.Attr{}
 			if p.tok.kind == .lsbr {
 				attr = p.attribute()
 			}
@@ -132,7 +130,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 		}
 		mod: p.mod
 	}
-	var ret := 0
+	mut ret := 0
 	if p.builtin_mod && t.name in table.builtin_type_names {
 		// this allows overiding the builtins type
 		// with the real struct type info parsed from builtin
@@ -158,7 +156,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
 	}
 }
 
-fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
+fn (mut p Parser) struct_init(short_syntax bool) ast.StructInit {
 	first_pos := p.tok.position()
 	typ := if short_syntax { table.void_type } else { p.parse_type() }
 	p.expr_mod = ''
@@ -167,17 +165,17 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
 	if !short_syntax {
 		p.check(.lcbr)
 	}
-	var fields := []ast.StructInitField
-	var i := 0
-	is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr	// `Vec{a,b,c}
+	mut fields := []ast.StructInitField
+	mut i := 0
+	is_short_syntax := p.peek_tok.kind != .colon && p.tok.kind != .rcbr // `Vec{a,b,c}
 	// p.warn(is_short_syntax.str())
 	for p.tok.kind != .rcbr {
 		p.check_comment()
-		var field_name := ''
+		mut field_name := ''
 		if is_short_syntax {
 			expr := p.expr(0)
+			// name will be set later in checker
 			fields << ast.StructInitField{
-				// name will be set later in checker
 				expr: expr
 				pos: expr.position()
 			}
@@ -221,28 +219,57 @@ fn (var p Parser) struct_init(short_syntax bool) ast.StructInit {
 	return node
 }
 
-fn (var p Parser) interface_decl() ast.InterfaceDecl {
+fn (mut p Parser) interface_decl() ast.InterfaceDecl {
 	is_pub := p.tok.kind == .key_pub
 	if is_pub {
 		p.next()
 	}
-	p.next()	// `interface`
+	p.next() // `interface`
 	interface_name := p.check_name()
+	//println('interface decl $interface_name')
 	p.check(.lcbr)
-	var field_names := []string
+	// Declare the type
+	t := table.TypeSymbol{
+		kind: .interface_
+		name: interface_name
+		info: table.Struct{
+			//is_interface: true
+		}
+	}
+	typ := p.table.register_type_symbol(t)
+	ts := p.table.get_type_symbol(typ) // TODO t vs ts
+	// Parse methods
+	mut methods := []ast.FnDecl
 	for p.tok.kind != .rcbr && p.tok.kind != .eof {
 		line_nr := p.tok.line_nr
 		name := p.check_name()
-		field_names << name
-		p.fn_args()
-		if p.tok.kind == .name && p.tok.line_nr == line_nr {
-			p.parse_type()
+		println(name)
+		// field_names << name
+		args2, _ := p.fn_args()
+		mut args := [table.Arg{
+			name: 'x'
+			typ: typ
+		}]
+		args << args2
+		mut method := ast.FnDecl{
+			name: name
+			args: args
+			return_type: table.void_type
 		}
+		if p.tok.kind == .name && p.tok.line_nr == line_nr {
+			method.return_type = p.parse_type()
+		}
+		methods << method
+		//println('register method $name')
+		ts.register_method(table.Fn{
+			name: name
+			args: args
+			return_type: method.return_type
+		})
 	}
 	p.check(.rcbr)
 	return ast.InterfaceDecl{
 		name: interface_name
-		field_names: field_names
+		methods: methods
 	}
 }
-
diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v
index 6146ee18dc..5dad83db0c 100644
--- a/vlib/v/table/atypes.v
+++ b/vlib/v/table/atypes.v
@@ -16,7 +16,7 @@ import v.ast
 
 pub type Type int
 
-pub type TypeInfo = Array | ArrayFixed | Map | Struct | MultiReturn | Alias | Enum | SumType | FnType
+pub type TypeInfo = Array | ArrayFixed | Map | Struct | Interface | MultiReturn | Alias | Enum | SumType | FnType
 
 pub struct TypeSymbol {
 pub:
@@ -160,10 +160,18 @@ pub const (
 
 pub const (
 	integer_type_idxs = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
-		u16_type_idx, u32_type_idx, u64_type_idx]
+		u16_type_idx
+	u32_type_idx
+	u64_type_idx
+	]
 	float_type_idxs   = [f32_type_idx, f64_type_idx]
 	number_type_idxs  = [i8_type_idx, i16_type_idx, int_type_idx, i64_type_idx, byte_type_idx,
-		u16_type_idx, u32_type_idx, u64_type_idx, f32_type_idx, f64_type_idx]
+		u16_type_idx
+	u32_type_idx
+	u64_type_idx
+	f32_type_idx
+	f64_type_idx
+	]
 	pointer_type_idxs = [voidptr_type_idx, byteptr_type_idx, charptr_type_idx]
 	string_type_idxs  = [string_type_idx, ustring_type_idx]
 )
@@ -194,8 +202,10 @@ pub const (
 
 pub const (
 	builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64',
-		'u16', 'u32', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
-		'map', 'struct', 'mapnode', 'size_t']
+		'u16'
+	'u32', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array',
+		'array_fixed', 'map'
+	'struct', 'mapnode', 'size_t']
 )
 
 pub struct MultiReturn {
@@ -242,6 +252,7 @@ pub enum Kind {
 	alias
 	enum_
 	function
+	interface_
 }
 
 pub fn (t &TypeSymbol) str() string {
@@ -251,60 +262,40 @@ pub fn (t &TypeSymbol) str() string {
 [inline]
 pub fn (t &TypeSymbol) enum_info() Enum {
 	match t.info {
-		Enum {
-			return it
-		}
-		else {
-			panic('TypeSymbol.enum_info(): no enum info for type: $t.name')
-		}
+		Enum { return it }
+		else { panic('TypeSymbol.enum_info(): no enum info for type: $t.name') }
 	}
 }
 
 [inline]
 pub fn (t &TypeSymbol) mr_info() MultiReturn {
 	match t.info {
-		MultiReturn {
-			return it
-		}
-		else {
-			panic('TypeSymbol.mr_info(): no multi return info for type: $t.name')
-		}
+		MultiReturn { return it }
+		else { panic('TypeSymbol.mr_info(): no multi return info for type: $t.name') }
 	}
 }
 
 [inline]
 pub fn (t &TypeSymbol) array_info() Array {
 	match t.info {
-		Array {
-			return it
-		}
-		else {
-			panic('TypeSymbol.array_info(): no array info for type: $t.name')
-		}
+		Array { return it }
+		else { panic('TypeSymbol.array_info(): no array info for type: $t.name') }
 	}
 }
 
 [inline]
 pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
 	match t.info {
-		ArrayFixed {
-			return it
-		}
-		else {
-			panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name')
-		}
+		ArrayFixed { return it }
+		else { panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name') }
 	}
 }
 
 [inline]
 pub fn (t &TypeSymbol) map_info() Map {
 	match t.info {
-		Map {
-			return it
-		}
-		else {
-			panic('TypeSymbol.map_info(): no map info for type: $t.name')
-		}
+		Map { return it }
+		else { panic('TypeSymbol.map_info(): no map info for type: $t.name') }
 	}
 }
 
@@ -313,7 +304,7 @@ pub fn (t TypeSymbol) str() string {
 	return t.name
 }
 */
-pub fn (var t Table) register_builtin_type_symbols() {
+pub fn (mut t Table) register_builtin_type_symbols() {
 	// reserve index 0 so nothing can go there
 	// save index check, 0 will mean not found
 	t.register_type_symbol(TypeSymbol{
@@ -445,99 +436,40 @@ pub fn (t &TypeSymbol) is_number() bool {
 
 pub fn (k Kind) str() string {
 	k_str := match k {
-		.placeholder {
-			'placeholder'
-		}
-		.void {
-			'void'
-		}
-		.voidptr {
-			'voidptr'
-		}
-		.charptr {
-			'charptr'
-		}
-		.byteptr {
-			'byteptr'
-		}
-		.struct_ {
-			'struct'
-		}
-		.int {
-			'int'
-		}
-		.i8 {
-			'i8'
-		}
-		.i16 {
-			'i16'
-		}
-		.i64 {
-			'i64'
-		}
-		.byte {
-			'byte'
-		}
-		.u16 {
-			'u16'
-		}
-		.u32 {
-			'u32'
-		}
-		.u64 {
-			'u64'
-		}
-		.f32 {
-			'f32'
-		}
-		.f64 {
-			'f64'
-		}
-		.string {
-			'string'
-		}
-		.ustring {
-			'ustring'
-		}
-		.char {
-			'char'
-		}
-		.bool {
-			'bool'
-		}
-		.none_ {
-			'none'
-		}
-		.array {
-			'array'
-		}
-		.array_fixed {
-			'array_fixed'
-		}
-		.map {
-			'map'
-		}
-		.multi_return {
-			'multi_return'
-		}
-		.sum_type {
-			'sum_type'
-		}
-		.alias {
-			'alias'
-		}
-		.enum_ {
-			'enum'
-		}
-		else {
-			'unknown'
-		}
+		.placeholder { 'placeholder' }
+		.void { 'void' }
+		.voidptr { 'voidptr' }
+		.charptr { 'charptr' }
+		.byteptr { 'byteptr' }
+		.struct_ { 'struct' }
+		.int { 'int' }
+		.i8 { 'i8' }
+		.i16 { 'i16' }
+		.i64 { 'i64' }
+		.byte { 'byte' }
+		.u16 { 'u16' }
+		.u32 { 'u32' }
+		.u64 { 'u64' }
+		.f32 { 'f32' }
+		.f64 { 'f64' }
+		.string { 'string' }
+		.char { 'char' }
+		.bool { 'bool' }
+		.none_ { 'none' }
+		.array { 'array' }
+		.array_fixed { 'array_fixed' }
+		.map { 'map' }
+		.multi_return { 'multi_return' }
+		.sum_type { 'sum_type' }
+		.alias { 'alias' }
+		.enum_ { 'enum' }
+		else { 'unknown' }
 	}
 	return k_str
 }
 
 pub fn (kinds []Kind) str() string {
-	var kinds_str := ''
+	mut kinds_str := ''
 	for i, k in kinds {
 		kinds_str += k.str()
 		if i < kinds.len - 1 {
@@ -554,6 +486,10 @@ pub mut:
 	is_union   bool
 }
 
+pub struct Interface {
+	gen_types []string
+}
+
 pub struct Enum {
 pub:
 	vals []string
@@ -604,7 +540,7 @@ pub:
 pub fn (table &Table) type_to_str(t Type) string {
 	sym := table.get_type_symbol(t)
 	if sym.kind == .multi_return {
-		var res := '('
+		mut res := '('
 		mr_info := sym.info as MultiReturn
 		for i, typ in mr_info.types {
 			res += table.type_to_str(typ)
@@ -615,7 +551,7 @@ pub fn (table &Table) type_to_str(t Type) string {
 		res += ')'
 		return res
 	}
-	var res := sym.name
+	mut res := sym.name
 	if sym.kind == .array {
 		res = res.replace('array_', '[]')
 	} else if sym.kind == .map {
diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v
index bbf1977c30..759786d50a 100644
--- a/vlib/v/tests/interface_test.v
+++ b/vlib/v/tests/interface_test.v
@@ -22,12 +22,40 @@ fn (d Dog) name() string {
 	return 'Dog'
 }
 
-fn test_todo() {}
+fn test_todo() {
+	if true {}
+	//
+	else{}
+}
 
 interface Speaker {
-	name ()string
+	name() string
 	speak()
+}
+
+/*
+fn perform_speak(s Speaker) {
+	s.speak()
+	assert true
+	/*
+	name := s.name()
+       assert name == 'Dog' || name == 'Cat'
+       println(s.name())
+*/
+}
+
+fn test_perform_speak() {
+	dog := Dog{}
+	perform_speak(dog)
+	cat := Cat{}
+	perform_speak(cat)
+	// perform_speakers([dog, cat])
+	/*
+	f := Foo {
+		speaker: dog
 	}
+*/
+}
 
 /*
 interface Speak2er {
@@ -40,37 +68,8 @@ struct Foo {
 	speakers []Speaker
 }
 
-fn perform_speak(s Speaker) {
-	if true {
-		// QTODO
-		return
-	}
-	s.speak()
-	assert true
-	name := s.name()
-	assert name == 'Dog' || name == 'Cat'
-	println(s.name())
-}
-
 fn perform_speakers(speakers []Speaker) {}
 
-fn test_perform_speak() {
-	if true {
-		// QTODO
-		return
-	}
-	dog := Dog{}
-	perform_speak(dog)
-	cat := Cat{}
-	perform_speak(cat)
-	// perform_speakers([dog, cat])
-	/*
-	f := Foo {
-		speaker: dog
-	}
-	*/
-
-}
 
 interface Register {
 	register()}
@@ -93,3 +92,4 @@ fn test_register() {
 	handle_reg(f)
 }
 */
+*/