Type Operators (or something like that)...

BlitzMax Forums/BlitzMax Programming/Type Operators (or something like that)...

fredborg(Posted 2005) [#1]
Hi,

I was wondering whether it at some point will be (or maybe already is) possible to specify type operators, which use regular mathematical/boolean syntax?

Perhaps my terminology isn't right, so here is a small example:
Type Funky
  Field a:Float,b:Float
  Method operator*(f:Funky)
    Return self.a*f.a + self.b*f.b
  EndMethod
  Method operator>(f:Funky)
    Return self.a+self.b>f.a+f.b
  EndMethod
  '
  ' Or alternatively
  ' 
  Operator *(f:Funky)
    Return self.a*f.a + self.b*f.b
  EndOperator
  Operator >(f:Funky)
    Return self.a+self.b>f.a+f.b
  EndOperator
EndType

x:Funky = New Funky
x.a = 1
x.b = 23

y:Funky = New Funky
y.a = 4
y.b = 2

'
' This would calculate:
' 1*4 + 23*2
' And output the result (50) to the output window
Print x*y

'
' And this would print 1 (as in True)
Print x>y
It would be useful for all these sorts of standard (or specialized) maths you often have to do on types.


SurreaL(Posted 2005) [#2]
what you are asking about is essentially operator overloading.. and well, that'd be pretty cool :)


AaronK(Posted 2005) [#3]
Operator overloading is pretty nice, but it's open to so much abuse by people who really don't understand it. They think it's a nifty way to save typing so would make an operator that added an object to a list or something stupid like that. Down the track this sort of use comes and bites you on the arse.

I'd almost suggest not having it in BlitzMax.


Extron(Posted 2005) [#4]
You can't overloading operator and function.

But you can name operator* to Mult, operator+ to Add etc... like this :
' ************************************************************************
' CLASS
' ************************************************************************
' TVECTOR
' ************************************************************************
Type TVector
	Const VINVALID:Byte=0 ; Const VDEFAULT:Byte=1 ; Const VUNIT:Byte=2
	Field _x:Double , _y:Double , _z:Double
	Field _Status:Byte
	
	'Method New()
	'	_x=0.0 ; _y=0.0 ; _z=0.0 ; _Status=VINVALID
	'End Method
	' ********************************************************************
	' Constructor
	' ********************************************************************
	Function Constructor:TVector(a:Double, b:Double, c:Double)
		result:TVector=New TVector
		result._x=a ; result._y=b ; result._z=c
		result._Status=VDEFAULT
		Return result
	End Function
	Function Constructor1:TVector(v:TVector)
		result:TVector=New TVector
		result._x=v._x ; result._y=v._y ; result._z=v._z ; result._Status=v._Status
		Return result
	End Function
	' ********************************************************************
	' Selectors
	' ********************************************************************
	Method x:Double()
		Return _x
	End Method
	Method y:Double()
		Return _y
	End Method
	Method z:Double()
		Return _z
	End Method
	Method isUnit()
		Return _Status=VUNIT
	End Method
	Method isDefault()
		Return _Status=VDEFAULT
	End Method
	Method isValid()
		Return _Status<>VINVALID
	End Method
	' ********************************************************************
	' Magnitude
	' ********************************************************************
	Method mag:Double()
		If isValid() Then
			If isUnit() Then
				Return 1.0
			Else
				Return Sqr(x()*x() + y()*y() + z()*z())
			EndIf
		Else
			Return 0.0
		EndIf
	End Method
	Method magSqr:Double()
		If isValid() Then
			If isUnit() Then
				Return 1.0
			Else
				Return x()*x() + y()*y() + z()*z()
			EndIf
		Else
			Return 0.0
		EndIf
	End Method	
	' ********************************************************************
	' Dot or scalar product
	' ********************************************************************
	Function dot1:Double(v1:TVector, v2:TVector)
		Return v1.dot(v2)
	End Function
	Method dot:Double(v:TVector)
		If isValid() And v.isValid() Then
			Return x()*v.x() + y()*v.y() + z()*v.z()
		Else
			Return 0.0
		EndIf
	End Method
	' ********************************************************************
	' Distance between two vectors
	' ********************************************************************
	Method dist:Double(v:TVector)		
		VEC:TVector=TVector.Constructor((_x-v._x),(_y-v._y),(_z-v._z))
		Return VEC.mag()		
	End Method
	Method distSqr:Double(v:TVector)
		VEC:TVector=TVector.Constructor((_x-v._x),(_y-v._y),(_z-v._z))
		Return VEC.magSqr()
	End Method
	' ********************************************************************
	' Make a unit vector
	' ********************************************************************
	Method unit:TVector()
		If isDefault() Then
			rep:Double=mag()
				If rep<EPSILON Then
					_x=0.0
					_y=0.0
					_z=0.0
				Else
					temp:Double=1.0/rep
					_x:*temp
					_y:*temp
					_z:*temp
				EndIf
				_Status = VUNIT;
		EndIf
		Return Self
	End Method
	Function unit1:TVector(v:TVector)
		VEC:TVector=TVector.Constructor(v._x, v._y, v._z)
		Return VEC.unit()
	End Function
	Function unit2:TVector(v:TVector, result:TVector)
		result._x=v._x ; result._y=v._y ; result._z=v._z ; result._Status=v._Status
		Return result.unit()
	End Function
	' ********************************************************************
	' Make a default vector
	' ********************************************************************	
	Method V_defaut:TVector()
		If isUnit() Then
			_Status = VDEFAULT
		EndIf
		Return Self
	End Method
	Function V_defaut1:TVector(v:TVector)
		VEC:TVector=TVector.Constructor(v._x, v._y, v._z)
		Return VEC.V_defaut()
	End Function
	Function V_defaut2:TVector(v:TVector, result:TVector)
		result._x=v._x ; result._y=v._y ; result._z=v._z ; result._Status=v._Status
		Return result.V_defaut()
	End Function
	' ********************************************************************
	' Optimised arithmetic methods
	' Return a TVector (Function, don't operate with this TVector)
	' ********************************************************************
	' Addition 2 vectors and return new vector (Result = v1 + v2)
	Function Addition:TVector(v1:TVector, v2:TVector)
		result:TVector=New TVector
		If v1.isValid() And v2.isValid() Then
			result._x = v1._x + v2._x
			result._y = v1._y + v2._y
			result._z = v1._z + v2._z
			result._Status = VDEFAULT
		EndIf
		Return result
	End Function
	' Substract 2 vectors and return new vector (Result = v1 - v2)
	Function Substract:TVector(v1:TVector, v2:TVector)
		result:TVector=New TVector
		If v1.isValid() And v2.isValid() Then
			result._x = v1._x - v2._x
			result._y = v1._y - v2._y
			result._z = v1._z - v2._z
			result._Status = VDEFAULT
		EndIf
		Return result
	End Function
	' Crossproduct of 2 vectors and return new vector (Result = v1 * v2)
	Function Cross:TVector(v1:TVector, v2:TVector)
		result:TVector=New TVector
		If v1.isValid() And v2.isValid() Then
			result._x = v1._y * v2._z - v1._z * v2._y
			result._y = v1._z * v2._x - v1._x * v2._z
			result._z = v1._x * v2._y - v1._y * v2._x
			result._Status = VDEFAULT
		EndIf
		Return result
	End Function	
	' Invert a vector and return new vector (Result = -(v1))
	Function Invert:TVector(v1:TVector)
		result:TVector=New TVector
		If v1.isValid() Then
			result._x = - v1._x
			result._y = - v1._y
			result._z = - v1._z
			result._Status = VDEFAULT
		EndIf
		Return result
	End Function	
	' Multiply 1 vector by scale and return new vector (Result = v1 * scale)
	Function Multiply:TVector(v1:TVector, scale:Double)
		result:TVector=New TVector
		If v1.isValid() Then
			result._x = v1._x * scale
			result._y = v1._y * scale
			result._z = v1._z * scale
			result._Status = VDEFAULT
		EndIf
		Return result
	End Function
	' ********************************************************************
	' Operator
	' ( Method, operate with this TVector )
	' ********************************************************************
	' Negat this vector and return a vector ( result = - self ) (v2=v1.Negat())
	Method Negat:TVector()
		Return TVector.Invert(Self)
	End Method
	' Assign a vector to this vector ( self = v1 ) (v2=v2.Equal(v1))
	Method Equal:TVector(v1:TVector)
		_x=v1._x ; _y=v1._y ; _z=v1._z ; _Status=v1._Status
	End Method	
	' Add to this vector a vector and return this vector ( self :+ v1 ) (v2=v2.AddEqual(v1))
	Method AddEqual:TVector(v1:TVector)
		Return TVector.Addition(Self, v1)
	End Method
	' Sub to this vector a vector and return this vector ( self :- v1 ) (v2=v2.SubEqual(v1))
	Method SubEqual:TVector(v1:TVector)
		Return TVector.Substract(Self, v1)
	End Method
	' Mult this vector by a vector and return this vector (Crossproduct) ( self :* v1 ) (v2=v2.MultEqualVec(v1))
	Method MultEqualVec:TVector(v1:TVector)
		Return TVector.Cross(Self, v1)
	End Method
	' Mult this vector by a val and return this vector ( self :* value ) (v2=v2.MultEqualVal(scale))
	Method MultEqualVal:TVector(scale:Double)
		Return TVector.Multiply(Self, scale)
	End Method
	' Add to this vector a vector and return a vector ( result = self + v1 ) (v3=v1.Add(v2))
	Method Add:TVector(v1:TVector)
		Return TVector.Addition(Self, v1)
	End Method
	' Sub to this vector a vector and return a vector ( result = self - v1 ) (v3=v1.Sub(v2))
	Method Sub:TVector(v1:TVector)
		Return TVector.Substract(Self, v1)
	End Method	
	' Mult to this vector a vector and return a vector (Crossproduct) ( result = self * v1 ) (v3=v1.MultVec(v2))
	Method MultVec:TVector(v1:TVector)
		Return TVector.Cross(Self, v1)
	End Method	
	' Mult to this vector by a value and return a vector ( result = self * scale ) (v3=v1.MultVal(scale))
	Method MultVal:TVector(scale:Double)
		Return TVector.Multiply(Self, scale)
	End Method
End Type


It's complicated, but it work. :)

I agree with Aaronk.


fredborg(Posted 2005) [#5]
Indeed you can do like you do, and it works without any problems, but it isn't as intuitive IMO.

Arguing that something shouldn't be possible because someone might not know how to use it, is like people keeping to say Goto should be removed because they think it's ugly and bad programming practise to use it.

I'm not saying it's a MUST, just asking if it might become available in the future, because I personally could see it being very useful.


AaronK(Posted 2005) [#6]
@fredborg
I agree, it IS like saying goto should be removed. That's why we have various programming languages. They all have different ways of achieving things cause someone thought that it'd be best "their" way. So if a language doesn't have goto's does that mean they're stupid cause someone might have wanted it. No.

If a language doesn't have multiple inheritence are they stupid if the reasoning was that it complicates design? No.

Also, I never once said it shouldn't be in there...I said it was NICE, but open to abuse.

Aaron


N(Posted 2005) [#7]
I never once said it shouldn't be in there

I'd almost suggest not having it in BlitzMax.


If you hadn't said 'almost', I'd be whippin' you right about now ;)

That said, I think operator overloading would be a perfectly reasonable addition to BlitzMax. People want to abuse it? So be it, it's their choice. Choice is better than not having one at all.


Bot Builder(Posted 2005) [#8]
It might be ok to add, but I'll agree it is very often abused. for instance, cout and cin confused me forever because they were the bitshift operators and it made no sense. Sure I could use it but it was pretty odd. Anyway, operator overloads are only truely useful in cases where the objects are mathematic like matrices, quaternions, vectors, etc. And even in those cases many of the overloads aren't really necissary, and rarely used.

Much more important is function overloads, private type members, and properties.