Repository: goby-lang/goby
Pull request #838 (2020-03-29 13:37:56)

Add arg checking helper
- Add `vm.checkArgTypes` for checking built-in methods' argument types
- Replace most of the manual type checkings with the new helper
- Some refactorings for reducing local variable usages


Patch:
diff --git a/vm/array.go b/vm/array.go
index b9ac081..542b698 100644
--- a/vm/array.go
+++ b/vm/array.go
@@ -144,16 +144,13 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			arr := receiver.(*ArrayObject)
-
-			copiesNumber, ok := args[0].(*IntegerObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			return arr.concatenateCopies(t, copiesNumber)
-
+			return receiver.(*ArrayObject).concatenateCopies(t, args[0].Value().(int))
 		},
 	},
 	{
@@ -266,14 +263,14 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentRange, 2, 3, aLen)
 			}
 
-			i := args[0]
-			index, ok := i.(*IntegerObject)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
-			indexValue := index.value
+			indexValue := args[0].Value().(int)
 			arr := receiver.(*ArrayObject)
 
 			// <Three Argument Case>
@@ -282,10 +279,10 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 			if aLen == 3 {
 				// Negative index value too small
 				if indexValue < 0 {
-					if arr.normalizeIndex(index) == -1 {
+					if arr.normalizeIndex(indexValue) == -1 {
 						return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.TooSmallIndexValue, indexValue, -arr.Len())
 					}
-					indexValue = arr.normalizeIndex(index)
+					indexValue = arr.normalizeIndex(indexValue)
 				}
 
 				c := args[1]
@@ -604,15 +601,14 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			i := args[0]
-			index, ok := i.(*IntegerObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
 			arr := receiver.(*ArrayObject)
-			normalizedIndex := arr.normalizeIndex(index)
+			normalizedIndex := arr.normalizeIndex(args[0].Value().(int))
 
 			if normalizedIndex == -1 {
 				return NULL
@@ -847,18 +843,20 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 				return arr.Elements[0]
 			}
 
-			arg, ok := args[0].(*IntegerObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			if arg.value < 1 {
-				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeValue, arg.value)
+			value := args[0].Value().(int)
+
+			if value < 1 {
+				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeValue, value)
 			}
 
-			if arrLength > arg.value {
-				return t.vm.InitArrayObject(arr.Elements[:arg.value])
+			if arrLength > value {
+				return t.vm.InitArrayObject(arr.Elements[:value])
 			}
 			return arr
 
@@ -977,13 +975,13 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 			if aLen == 0 {
 				sep = ""
 			} else {
-				arg, ok := args[0].(*StringObject)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+				if typeErr != nil {
+					return typeErr
 				}
 
-				sep = arg.value
+				sep = args[0].Value().(string)
 			}
 
 			arr := receiver.(*ArrayObject)
@@ -1022,18 +1020,22 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 				return arr.Elements[arrLength-1]
 			}
 
-			arg, ok := args[0].(*IntegerObject)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
-			if arg.value < 1 {
-				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeValue, arg.value)
+			value := args[0].Value().(int)
+
+
+			if value < 1 {
+				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeValue, value)
 			}
 
-			if arrLength > arg.value {
-				return t.vm.InitArrayObject(arr.Elements[arrLength-arg.value : arrLength])
+			if arrLength > value {
+				return t.vm.InitArrayObject(arr.Elements[arrLength-value : arrLength])
 			}
 			return arr
 
@@ -1338,11 +1340,13 @@ var builtinArrayInstanceMethods = []*BuiltinMethodObject{
 			if aLen == 0 {
 				rotate = 1
 			} else {
-				arg, ok := args[0].(*IntegerObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
+
+				if typeErr != nil {
+					return typeErr
 				}
-				rotate = arg.value
+
+				rotate = args[0].Value().(int)
 			}
 
 			if rotate < 0 {
@@ -1628,11 +1632,11 @@ func (a *ArrayObject) ToJSON(t *Thread) string {
 }
 
 // concatenateCopies returns a array composed of N copies of the array
-func (a *ArrayObject) concatenateCopies(t *Thread, n *IntegerObject) Object {
+func (a *ArrayObject) concatenateCopies(t *Thread, n int) Object {
 	aLen := len(a.Elements)
-	result := make([]Object, 0, aLen*n.value)
+	result := make([]Object, 0, aLen*n)
 
-	for i := 0; i < n.value; i++ {
+	for i := 0; i < n; i++ {
 		result = append(result, a.Elements...)
 	}
 
@@ -1641,14 +1645,13 @@ func (a *ArrayObject) concatenateCopies(t *Thread, n *IntegerObject) Object {
 
 // recursive indexed access - see ArrayObject#dig documentation.
 func (a *ArrayObject) dig(t *Thread, keys []Object, sourceLine int) Object {
-	currentKey := keys[0]
-	intCurrentKey, ok := currentKey.(*IntegerObject)
+	typeErr := t.vm.checkArgTypes(keys, sourceLine, classes.IntegerClass)
 
-	if !ok {
-		return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, currentKey.Class().Name)
+	if typeErr != nil {
+		return typeErr
 	}
 
-	normalizedIndex := a.normalizeIndex(intCurrentKey)
+	normalizedIndex := a.normalizeIndex(keys[0].Value().(int))
 
 	if normalizedIndex == -1 {
 		return NULL
@@ -1677,16 +1680,17 @@ func (a *ArrayObject) index(t *Thread, args []Object, sourceLine int) Object {
 		return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentRange, 1, 2, aLen)
 	}
 
-	i := args[0]
-	index, ok := i.(*IntegerObject)
-	arrLength := a.Len()
+	typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-	if !ok {
-		return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+	if typeErr != nil {
+		return typeErr
 	}
 
-	if index.value < 0 && index.value < -arrLength {
-		return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.TooSmallIndexValue, index.value, -arrLength)
+	index := args[0].Value().(int)
+	arrLength := a.Len()
+
+	if index < 0 && index < -arrLength {
+		return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.TooSmallIndexValue, index, -arrLength)
 	}
 
 	/* Validation for the second argument if exists */
@@ -1707,7 +1711,7 @@ func (a *ArrayObject) index(t *Thread, args []Object, sourceLine int) Object {
 		 *  a = [1, 2, 3, 4, 5]
 		 *  a[5, 5] #=> []
 		 */
-		if index.value > 0 && index.value == arrLength {
+		if index > 0 && index == arrLength {
 			return t.vm.InitArrayObject([]Object{})
 		}
 	}
@@ -1781,9 +1785,8 @@ func (a *ArrayObject) Less(i, j int) bool {
 // 1. if the index is between o and the index length, returns the index
 // 2. if it's a negative value (within bounds), returns the normalized positive version
 // 3. if it's out of bounds (either positive or negative), returns -1
-func (a *ArrayObject) normalizeIndex(objectIndex *IntegerObject) int {
+func (a *ArrayObject) normalizeIndex(index int) int {
 	aLength := len(a.Elements)
-	index := objectIndex.value
 
 	// out of bounds
 
diff --git a/vm/class.go b/vm/class.go
index 4014152..53bd159 100644
--- a/vm/class.go
+++ b/vm/class.go
@@ -186,7 +186,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			if c == module {
@@ -225,7 +225,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			if c == module {
@@ -264,7 +264,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			if c == module {
@@ -303,7 +303,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			if c == module {
@@ -481,7 +481,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok || !module.isModule {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			class = receiver.SingletonClass()
@@ -547,7 +547,7 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 			module, ok := args[0].(*RClass)
 
 			if !ok || !module.isModule {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "a module", args[0].Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.ModuleClass, args[0].Class().Name)
 			}
 
 			switch r := receiver.(type) {
@@ -664,13 +664,13 @@ var builtinModuleCommonClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			arg, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, arg.Class().Name)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if err != nil {
+				return err
 			}
 
-			r := receiver
-			if r.findMethod(arg.value) == nil {
+			if receiver.findMethod(args[0].Value().(string)) == nil {
 				return FALSE
 			}
 			return TRUE
@@ -926,13 +926,13 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 			case 0:
 				os.Exit(0)
 			case 1:
-				exitCode, ok := args[0].(*IntegerObject)
+				err := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+				if err != nil {
+					return err
 				}
 
-				os.Exit(exitCode.value)
+				os.Exit(args[0].Value().(int))
 			default:
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentLess, 1, aLen)
 			}
@@ -1097,15 +1097,16 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 			switch aLen {
 			case 0:
 			case 1:
-				if args[0].Class().Name == classes.BlockClass {
-					blockObj := args[0].(*BlockObject)
-					blockFrame = newNormalCallFrame(blockObj.instructionSet, blockObj.instructionSet.filename, sourceLine)
-					blockFrame.ep = blockObj.ep
-					blockFrame.self = receiver
-					blockFrame.isBlock = true
-				} else {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.BlockClass, args[0].Class().Name)
+				err := t.vm.checkArgTypes(args, sourceLine, classes.BlockClass)
+
+				if err != nil {
+					return err
 				}
+				blockObj := args[0].(*BlockObject)
+				blockFrame = newNormalCallFrame(blockObj.instructionSet, blockObj.instructionSet.filename, sourceLine)
+				blockFrame.ep = blockObj.ep
+				blockFrame.self = receiver
+				blockFrame.isBlock = true
 			default:
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentLess, 1, aLen)
 			}
@@ -1148,13 +1149,13 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			arg, isStr := args[0].(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !isStr {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if err != nil {
+				return err
 			}
 
-			obj, ok := receiver.InstanceVariableGet(arg.value)
+			obj, ok := receiver.InstanceVariableGet(args[0].Value().(string))
 
 			if !ok {
 				return NULL
@@ -1186,14 +1187,15 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 2, len(args))
 			}
 
-			argName, isStr := args[0].(*StringObject)
-			obj := args[1]
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !isStr {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if err != nil {
+				return err
 			}
 
-			receiver.InstanceVariableSet(argName.value, obj)
+			obj := args[1]
+
+			receiver.InstanceVariableSet(args[0].Value().(string), obj)
 
 			return obj
 
@@ -1347,22 +1349,19 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 			case 0:
 				return t.vm.initFloatObject(rand.Float64())
 			case 1:
-				_, ok := args[0].(*IntegerObject)
+				err := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+				if err != nil {
+					return err
 				}
+
 				return t.vm.InitIntegerObject(rand.Intn(args[0].Value().(int)))
 			case 2:
-				_, minOk := args[0].(*IntegerObject)
 
-				if !minOk {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
-				}
-				_, maxOk := args[1].(*IntegerObject)
+				err := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass, classes.IntegerClass)
 
-				if !maxOk {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[1].Class().Name)
+				if err != nil {
+					return err
 				}
 
 				return t.vm.InitIntegerObject(rand.Intn(args[1].Value().(int)-args[0].Value().(int)+1) + args[0].Value().(int))
@@ -1530,13 +1529,13 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentMore, 1, 0)
 			}
 
-			name, ok := args[0].(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if err != nil {
+				return err
 			}
 
-			t.sendMethod(name.value, len(args)-1, blockFrame, sourceLine)
+			t.sendMethod(args[0].Value().(string), len(args)-1, blockFrame, sourceLine)
 
 			return t.Stack.top().Target
 
diff --git a/vm/concurrent_hash.go b/vm/concurrent_hash.go
index 7be4863..b041994 100644
--- a/vm/concurrent_hash.go
+++ b/vm/concurrent_hash.go
@@ -46,11 +46,10 @@ var builtinConcurrentHashClassMethods = []*BuiltinMethodObject{
 				return t.vm.initConcurrentHashObject(make(map[string]Object))
 			}
 
-			arg := args[0]
-			hashArg, ok := arg.(*HashObject)
+			hashArg, ok := args[0].(*HashObject)
 
 			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.HashClass, arg.Class().Name)
+				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.HashClass, args[0].Class().Name)
 			}
 
 			return t.vm.initConcurrentHashObject(hashArg.Pairs)
@@ -79,16 +78,15 @@ var builtinConcurrentHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			i := args[0]
-			key, ok := i.(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, i.Class().Name)
+			if err != nil {
+				return err
 			}
 
 			h := receiver.(*ConcurrentHashObject)
 
-			value, ok := h.internalMap.Load(key.value)
+			value, ok := h.internalMap.Load(args[0].Value().(string))
 
 			if !ok {
 				return NULL
@@ -117,15 +115,14 @@ var builtinConcurrentHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 2, len(args))
 			}
 
-			k := args[0]
-			key, ok := k.(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, k.Class().Name)
+			if err != nil {
+				return err
 			}
 
 			h := receiver.(*ConcurrentHashObject)
-			h.internalMap.Store(key.value, args[1])
+			h.internalMap.Store(args[0].Value().(string), args[1])
 
 			return args[1]
 
@@ -147,15 +144,13 @@ var builtinConcurrentHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			h := receiver.(*ConcurrentHashObject)
-			d := args[0]
-			deleteKeyObject, ok := d.(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, d.Class().Name)
+			if err != nil {
+				return err
 			}
 
-			h.internalMap.Delete(deleteKeyObject.value)
+			receiver.(*ConcurrentHashObject).internalMap.Delete(args[0].Value().(string))
 
 			return NULL
 
@@ -226,15 +221,13 @@ var builtinConcurrentHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			h := receiver.(*ConcurrentHashObject)
-			i := args[0]
-			input, ok := i.(*StringObject)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, i.Class().Name)
+			if err != nil {
+				return err
 			}
 
-			if _, ok := h.internalMap.Load(input.value); ok {
+			if _, ok := receiver.(*ConcurrentHashObject).internalMap.Load(args[0].Value().(string)); ok {
 				return TRUE
 			}
 
diff --git a/vm/file.go b/vm/file.go
index 3915714..8473fd2 100644
--- a/vm/file.go
+++ b/vm/file.go
@@ -49,13 +49,13 @@ var builtinFileClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			fn, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
-			}
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			return t.vm.InitStringObject(filepath.Base(fn.value))
+			if err != nil {
+				return err
+			}
 
+			return t.vm.InitStringObject(filepath.Base(args[0].Value().(string)))
 		},
 	},
 	{
@@ -150,11 +150,13 @@ var builtinFileClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			fn, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
-			_, err := os.Stat(fn.value)
+
+			_, err := os.Stat(args[0].Value().(string))
 
 			if err != nil {
 				return FALSE
@@ -179,13 +181,13 @@ var builtinFileClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			fn, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
-			}
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			return t.vm.InitStringObject(filepath.Ext(fn.value))
+			if err != nil {
+				return err
+			}
 
+			return t.vm.InitStringObject(filepath.Ext(args[0].Value().(string)))
 		},
 	},
 	{
@@ -301,16 +303,20 @@ var builtinFileClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			fn, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
-			if !filepath.IsAbs(fn.value) {
-				fn.value = filepath.Join(t.vm.fileDir, fn.value)
+			fn := args[0].Value().(string)
+
+			if !filepath.IsAbs(fn) {
+				fn = filepath.Join(t.vm.fileDir, fn)
 			}
 
-			fs, err := os.Stat(fn.value)
+			fs, err := os.Stat(fn)
+
 			if err != nil {
 				return t.vm.InitErrorObject(errors.IOError, sourceLine, err.Error())
 			}
@@ -334,12 +340,13 @@ var builtinFileClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			fn, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			err := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if err != nil {
+				return err
 			}
 
-			d, f := filepath.Split(fn.value)
+			d, f := filepath.Split(args[0].Value().(string))
 
 			return t.vm.InitArrayObject([]Object{t.vm.InitStringObject(d), t.vm.InitStringObject(f)})
 
diff --git a/vm/go_map.go b/vm/go_map.go
index c4a4fcf..3a6304d 100644
--- a/vm/go_map.go
+++ b/vm/go_map.go
@@ -54,15 +54,13 @@ var builtinGoMapInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			key, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			m := receiver.(*GoMap).data
-
-			result, ok := m[key.value]
+			result, ok := receiver.(*GoMap).data[args[0].Value().(string)]
 
 			if !ok {
 				return NULL
diff --git a/vm/go_object.go b/vm/go_object.go
index bd2aab1..59de709 100644
--- a/vm/go_object.go
+++ b/vm/go_object.go
@@ -35,13 +35,13 @@ var builtinGoObjectInstanceMethods = []*BuiltinMethodObject{
 		// @return [Object]
 		Name: "go_func",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
-			s, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			funcName := s.value
+			funcName := args[0].Value().(string)
 			r := receiver.(*GoObject)
 
 			funcArgs, err := ConvertToGoFuncArgs(args[1:])
diff --git a/vm/hash.go b/vm/hash.go
index cc06656..c804f16 100644
--- a/vm/hash.go
+++ b/vm/hash.go
@@ -91,16 +91,15 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			i := args[0]
-			key, ok := i.(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, i.Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
 			h := receiver.(*HashObject)
 
-			value, ok := h.Pairs[key.value]
+			value, ok := h.Pairs[args[0].Value().(string)]
 
 			if !ok {
 				if h.Default != nil {
@@ -135,15 +134,15 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 			if len(args) != 2 {
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 2, len(args))
 			}
-			k := args[0]
-			key, ok := k.(*StringObject)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, k.Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
 			h := receiver.(*HashObject)
-			h.Pairs[key.value] = args[1]
+			h.Pairs[args[0].Value().(string)] = args[1]
 
 			return args[1]
 
@@ -329,15 +328,16 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			h := receiver.(*HashObject)
-			d := args[0]
-			deleteKey, ok := d.(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, d.Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			deleteKeyValue := deleteKey.value
+			deleteKeyValue := args[0].Value().(string)
+
+			h := receiver.(*HashObject)
+
 			if _, ok := h.Pairs[deleteKeyValue]; ok {
 				delete(h.Pairs, deleteKeyValue)
 			}
@@ -707,7 +707,6 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 				return t.builtinMethodYield(blockFrame, key).Target
 			}
 			return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, "The value was not found, and no block has been provided")
-
 		},
 	},
 	{
@@ -786,15 +785,13 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			h := receiver.(*HashObject)
-			i := args[0]
-			input, ok := i.(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, i.Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			if _, ok := h.Pairs[input.value]; ok {
+			if _, ok := receiver.(*HashObject).Pairs[args[0].Value().(string)]; ok {
 				return TRUE
 			}
 			return FALSE
@@ -1076,12 +1073,13 @@ var builtinHashInstanceMethods = []*BuiltinMethodObject{
 			if aLen == 0 {
 				sorted = false
 			} else {
-				s := args[0]
-				st, ok := s.(*BooleanObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.BooleanClass, s.Class().Name)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.BooleanClass)
+
+				if typeErr != nil {
+					return typeErr
 				}
-				sorted = st.value
+
+				sorted = args[0].Value().(bool)
 			}
 
 			h := receiver.(*HashObject)
@@ -1345,15 +1343,14 @@ func (h *HashObject) copy() Object {
 
 // recursive indexed access - see ArrayObject#dig documentation.
 func (h *HashObject) dig(t *Thread, keys []Object, sourceLine int) Object {
-	currentKey := keys[0]
-	stringCurrentKey, ok := currentKey.(*StringObject)
+	typeErr := t.vm.checkArgTypes(keys, sourceLine, classes.StringClass)
 
-	if !ok {
-		return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, currentKey.Class().Name)
+	if typeErr != nil {
+		return typeErr
 	}
 
 	nextKeys := keys[1:]
-	currentValue, ok := h.Pairs[stringCurrentKey.value]
+	currentValue, ok := h.Pairs[keys[0].Value().(string)]
 
 	if !ok {
 		return NULL
diff --git a/vm/http_client.go b/vm/http_client.go
index f5bcb7b..325208e 100644
--- a/vm/http_client.go
+++ b/vm/http_client.go
@@ -25,12 +25,13 @@ func builtinHTTPClientInstanceMethods() []*BuiltinMethodObject {
 					return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 				}
 
-				u, ok := args[0].(*StringObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, u.Class().Name)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+				if typeErr != nil {
+					return typeErr
 				}
 
-				resp, err := goClient.Get(u.value)
+				resp, err := goClient.Get(args[0].Value().(string))
 				if err != nil {
 					return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
 				}
@@ -51,24 +52,15 @@ func builtinHTTPClientInstanceMethods() []*BuiltinMethodObject {
 					return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 3, len(args))
 				}
 
-				u, ok := args[0].(*StringObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, u.Class().Name)
-				}
-
-				contentType, ok := args[1].(*StringObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, u.Class().Name)
-				}
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass, classes.StringClass, classes.StringClass)
 
-				body, ok := args[2].(*StringObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, u.Class().Name)
+				if typeErr != nil {
+					return typeErr
 				}
 
-				bodyR := strings.NewReader(body.value)
+				bodyR := strings.NewReader(args[2].Value().(string))
 
-				resp, err := goClient.Post(u.value, contentType.value, bodyR)
+				resp, err := goClient.Post(args[0].Value().(string), args[1].Value().(string), bodyR)
 				if err != nil {
 					return t.vm.InitErrorObject(errors.HTTPError, sourceLine, "Could not complete request, %s", err)
 				}
@@ -89,12 +81,13 @@ func builtinHTTPClientInstanceMethods() []*BuiltinMethodObject {
 					return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 				}
 
-				u, ok := args[0].(*StringObject)
-				if !ok {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, u.Class().Name)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+				if typeErr != nil {
+					return typeErr
 				}
 
-				resp, err := goClient.Head(u.value)
+				resp, err := goClient.Head(args[0].Value().(string))
 				if err != nil {
 					return t.vm.InitErrorObject(errors.HTTPError, sourceLine, couldNotCompleteRequest, err)
 				}
@@ -122,8 +115,10 @@ func builtinHTTPClientInstanceMethods() []*BuiltinMethodObject {
 					return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 				}
 
-				if args[0].Class().Name != httpRequestClass.Name {
-					return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, "HTTP Response", args[0].Class().Name)
+				typeErr := t.vm.checkArgTypes(args, sourceLine, httpRequestClass.Name)
+
+				if typeErr != nil {
+					return typeErr
 				}
 
 				goReq, err := requestGobyToGo(args[0])
diff --git a/vm/json.go b/vm/json.go
index d589f59..99267b3 100644
--- a/vm/json.go
+++ b/vm/json.go
@@ -18,17 +18,17 @@ var builtinJSONClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			j, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
+			jsonString := args[0].Value().(string)
+
 			var obj jsonObj
 			var objs []jsonObj
 
-			jsonString := j.value
-
 			err := json.Unmarshal([]byte(jsonString), &obj)
 
 			if err != nil {
@@ -58,17 +58,17 @@ var builtinJSONClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			j, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
+			jsonString := args[0].Value().(string)
+
 			var obj jsonObj
 			var objs []jsonObj
 
-			jsonString := j.value
-
 			err := json.Unmarshal([]byte(jsonString), &obj)
 
 			if err != nil {
diff --git a/vm/regexp.go b/vm/regexp.go
index 5925b8e..839de36 100644
--- a/vm/regexp.go
+++ b/vm/regexp.go
@@ -51,9 +51,10 @@ var builtInRegexpClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			arg, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, arg.Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
 			r := t.vm.initRegexpObject(args[0].ToString())
diff --git a/vm/string.go b/vm/string.go
index 1b1a1a8..f607448 100644
--- a/vm/string.go
+++ b/vm/string.go
@@ -55,13 +55,13 @@ var builtinStringClassMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentMore, 1, len(args))
 			}
 
-			formatObj, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			format := formatObj.value
+			format := args[0].Value().(string)
 			arguments := []interface{}{}
 
 			for _, arg := range args[1:] {
@@ -100,16 +100,13 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 		// @return [String]
 		Name: "+",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			right, ok := args[0].(*StringObject)
-
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			left := receiver.(*StringObject)
-			return t.vm.InitStringObject(left.value + right.value)
-
+			return t.vm.InitStringObject(receiver.Value().(string) + args[0].Value().(string))
 		},
 	},
 	{
@@ -123,20 +120,22 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 		// @return [String]
 		Name: "*",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass)
 
-			right, ok := args[0].(*IntegerObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			if right.value < 0 {
-				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeSecondValue, right.value)
+			right := args[0].Value().(int)
+
+			if right < 0 {
+				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.NegativeSecondValue, right)
 			}
 
 			var result string
 
 			left := receiver.(*StringObject)
-			for i := 0; i < right.value; i++ {
+			for i := 0; i < right; i++ {
 				result += left.value
 			}
 
@@ -155,14 +154,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 		// @return [Boolean]
 		Name: ">",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			right, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
 			left := receiver.(*StringObject)
-			if left.value > right.value {
+			if left.value > args[0].Value().(string) {
 				return TRUE
 			}
 
@@ -181,15 +180,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 		// @return [Boolean]
 		Name: "<",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			right, ok := args[0].(*StringObject)
-
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
 			left := receiver.(*StringObject)
-			if left.value < right.value {
+			if left.value < args[0].Value().(string) {
 				return TRUE
 			}
 
@@ -212,18 +210,18 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 		// @return [Integer]
 		Name: "<=>",
 		Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			right, ok := args[0].(*StringObject)
-
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
+			right := args[0].Value().(string)
 			left := receiver.(*StringObject)
 			switch {
-			case left.value < right.value:
+			case left.value < right:
 				return t.vm.InitIntegerObject(-1)
-			case left.value > right.value:
+			case left.value > right:
 				return t.vm.InitIntegerObject(1)
 			default:
 				return t.vm.InitIntegerObject(0)
@@ -355,14 +353,15 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 			if len(args) != 2 {
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 2, len(args))
 			}
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.IntegerClass, classes.StringClass)
 
-			index, ok := args[0].(*IntegerObject)
-
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.IntegerClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			indexValue := index.value
+			indexValue := args[0].Value().(int)
+			replaceStrValue := args[1].Value().(string)
+
 			str := receiver.(*StringObject).value
 			strLength := utf8.RuneCountInString(str)
 
@@ -370,13 +369,6 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.IndexOutOfRange, strconv.Itoa(indexValue))
 			}
 
-			replaceStr, ok := args[1].(*StringObject)
-
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[1].Class().Name)
-			}
-			replaceStrValue := replaceStr.value
-
 			// Negative Index Case
 			if indexValue < 0 {
 				if -indexValue > strLength {
@@ -456,13 +448,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			concatStr, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
 			str := receiver.(*StringObject).value
-			return t.vm.InitStringObject(str + concatStr.value)
+			return t.vm.InitStringObject(str + args[0].Value().(string))
 
 		},
 	},
@@ -505,15 +498,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			deleteStr, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
 			str := receiver.(*StringObject).value
-			return t.vm.InitStringObject(strings.Replace(str, deleteStr.value, "", -1))
-
+			return t.vm.InitStringObject(strings.Replace(str, args[0].Value().(string), "", -1))
 		},
 	},
 	{
@@ -716,13 +708,13 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			compareStr, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			compareStrValue := compareStr.value
+			compareStrValue := args[0].Value().(string)
 			compareStrLength := utf8.RuneCountInString(compareStrValue)
 
 			str := receiver.(*StringObject).value
@@ -785,13 +777,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			includeStr, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
 			str := receiver.(*StringObject).value
-			if strings.Contains(str, includeStr.value) {
+			if strings.Contains(str, args[0].Value().(string)) {
 				return TRUE
 			}
 
@@ -1339,13 +1332,14 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			separator, ok := args[0].(*StringObject)
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
+
+			if typeErr != nil {
+				return typeErr
 			}
 
 			str := receiver.(*StringObject).value
-			arr := strings.Split(str, separator.value)
+			arr := strings.Split(str, args[0].Value().(string))
 
 			var elements []Object
 			for i := 0; i < len(arr); i++ {
@@ -1374,13 +1368,13 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{
 				return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
 			}
 
-			compareStr, ok := args[0].(*StringObject)
+			typeErr := t.vm.checkArgTypes(args, sourceLine, classes.StringClass)
 
-			if !ok {
-				return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.StringClass, args[0].Class().Name)
+			if typeErr != nil {
+				return typeErr
 			}
 
-			compareStrValue := compareStr.value
+			compareStrValue := args[0].Value().(string)
 			compareStrLength := utf8.RuneCountInString(compareStrValue)
 
 			str := receiver.(*StringObject).value
diff --git a/vm/vm.go b/vm/vm.go
index ad34802..5adaaf3 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -14,6 +14,7 @@ import (
 	"github.com/goby-lang/goby/compiler/bytecode"
 	"github.com/goby-lang/goby/compiler/parser"
 	"github.com/goby-lang/goby/vm/classes"
+	"github.com/goby-lang/goby/vm/errors"
 )
 
 // Version stores current Goby version
@@ -403,3 +404,15 @@ func (vm *VM) testEval(t *testing.T, input, filepath string) Object {
 
 	return vm.mainThread.Stack.top().Target
 }
+
+func (vm *VM) checkArgTypes(args []Object, sourceLine int, types ...string) *Error {
+	for i, expectedType := range types {
+		className := args[i].Class().Name
+
+		if className != expectedType {
+			return vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, expectedType, className)
+		}
+	}
+
+	return nil
+}
\ No newline at end of file


Test patch:
diff --git a/vm/class_test.go b/vm/class_test.go
index 5758ab6..b1b2ad9 100644
--- a/vm/class_test.go
+++ b/vm/class_test.go
@@ -562,7 +562,7 @@ class Bar
   include Foo
 end
 	`
-	expected := `TypeError: Expect argument to be a module. got: Class`
+	expected := `TypeError: Expect argument to be Module. got: Class`
 
 	v := initTestVM()
 	evaluated := v.testEval(t, input, getFilename())
@@ -579,7 +579,7 @@ class Bar
   extend Foo
 end
 	`
-	expected := `TypeError: Expect argument to be a module. got: Class`
+	expected := `TypeError: Expect argument to be Module. got: Class`
 
 	v := initTestVM()
 	evaluated := v.testEval(t, input, getFilename())
@@ -739,7 +739,7 @@ func TestClassGreaterThanMethod(t *testing.T) {
 
 func TestClassGreaterThanMethodFail(t *testing.T) {
 	testsFail := []errorTestCase{
-		{`Array > 1`, "TypeError: Expect argument to be a module. got: Integer", 1},
+		{`Array > 1`, "TypeError: Expect argument to be Module. got: Integer", 1},
 	}
 
 	for i, tt := range testsFail {
@@ -799,7 +799,7 @@ func TestClassGreaterThanOrEqualMethod(t *testing.T) {
 
 func TestClassGreaterThanOrEqualMethodFail(t *testing.T) {
 	testsFail := []errorTestCase{
-		{`Array >= 1`, "TypeError: Expect argument to be a module. got: Integer", 1},
+		{`Array >= 1`, "TypeError: Expect argument to be Module. got: Integer", 1},
 	}
 
 	for i, tt := range testsFail {
@@ -859,7 +859,7 @@ func TestClassLesserThanMethod(t *testing.T) {
 
 func TestClassLesserThanMethodFail(t *testing.T) {
 	testsFail := []errorTestCase{
-		{`Array < 1`, "TypeError: Expect argument to be a module. got: Integer", 1},
+		{`Array < 1`, "TypeError: Expect argument to be Module. got: Integer", 1},
 	}
 
 	for i, tt := range testsFail {
@@ -919,7 +919,7 @@ func TestClassLesserThanOrEqualMethod(t *testing.T) {
 
 func TestClassLesserThanOrEqualMethodFail(t *testing.T) {
 	testsFail := []errorTestCase{
-		{`Array <= 1`, "TypeError: Expect argument to be a module. got: Integer", 1},
+		{`Array <= 1`, "TypeError: Expect argument to be Module. got: Integer", 1},
 	}
 
 	for i, tt := range testsFail {
diff --git a/vm/string_test.go b/vm/string_test.go
index fdc8a4b..9797f49 100644
--- a/vm/string_test.go
+++ b/vm/string_test.go
@@ -245,7 +245,7 @@ func TestStringOperationFail(t *testing.T) {
 		{`"Taipei"[1] = true`, "TypeError: Expect argument to be String. got: Boolean", 1},
 		{`"Taipei"[]`, "ArgumentError: Expect 1 argument(s). got: 0", 1},
 		{`"Taipei"[true] = 101`, "TypeError: Expect argument to be Integer. got: Boolean", 1},
-		{`"Taipei"[20] = 101`, "ArgumentError: Index value out of range. got: 20", 1},
+		{`"Taipei"[20] = "10"`, "ArgumentError: Index value out of range. got: 20", 1},
 		{`"Taipei"[-20] = "a"`, "ArgumentError: Index value out of range. got: -20", 1},
 	}