Properties on classes...

BlitzMax Forums/BlitzMax Programming/Properties on classes...

ziggy(Posted 2009) [#1]
I know this has been requested some times before but... Don't you think it would be ultra sexy to have them on BlitzMax?


GW(Posted 2009) [#2]
You mean like reflection?


ziggy(Posted 2009) [#3]
Yes, like reflection (that finally was implemented) and threading (wich was finally implemented too). Properties in classes is mostly the only thing I'm missing in BlitzMax.
EDIT: Now I remember reflection was not requested by the community, but added by Mark becouse of he wanted to add this feature to the language.


Brucey(Posted 2009) [#4]
So, what is a class property exactly?


ziggy(Posted 2009) [#5]
This are properties: http://en.wikipedia.org/wiki/Property_%28programming%29
and can make code much more readable, and makes the data validation a lot easier IMHO.

This vb.net example makes it very easy to understand:
Public Class Pen
 
    Dim m_Color As Integer 
 
    Public Property Color As Integer ' Public property
        Get
            Return m_Color
        End Get
        Set(ByVal Value As Integer)
            m_Color = Value
        End Set
    End Property
 
End Class


In BlitzMax could look something like:
 Type Pen
 
    Field _Color:Int
 
    Property Color:Int ' Public property
        Get
            Return _Color
        End Get
        Set(Value:Int)
            m_Color = Value
        End Set
    End Property
 
End Type



_Skully(Posted 2009) [#6]
Why not just create your own and link to them through a TList rather that adding a bunch of overhead to types as they are... I'd rather see private/public implemented personally


Brucey(Posted 2009) [#7]
I'd also like Private/Protected/Public fields. I think that would be far more useful as an overall language enhancement.

In BlitzMax could look something like

Well, I don't like the example ;-)
It is not at all easy to read!


GW(Posted 2009) [#8]
Except that Getters/Setters are evil!

http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html


ziggy(Posted 2009) [#9]
Public / Private / Protected is a must when using Properties. In fact, properties are the way to add validations when a class user is accesing a field!

Maybe you will like more a C# example?
class Pen
{
    private int m_Color; // private field
 
    public int Color   // public property
    {
        get
        {
            return m_Color;
        }
        set 
        {
            m_Color = value;
        }
    }
}

// accessing:
Pen pen = new Pen();
// ...
pen.Color = ~pen.Color; // bitwise complement ...
 
// another silly example:
pen.Color += 1; // a lot clearer than "pen.set_Color(pen.get_Color() + 1)"!



usually c++ coders don't see the benefits of properties becouse c++ does not have them... Anyway, I can't be the only one used to them (or liking them here??can't believe it!) This is a brief list of languages that support them: Delphi/Free Pascal, Visual Basic, C#, D, eC, Objective C 2.0, Python and Vala


Brucey(Posted 2009) [#10]
Well... I think :

VB
        Get
            Return m_Color


C#
        get
        {


max
        Get
            Return _Color

...all look terrible, syntax wise...

But I do agree that being able to do something like this :
pen.Color += 1

would be very cool indeed. :-)


_Skully(Posted 2009) [#11]
you mean like

pen.color:+1


?


ziggy(Posted 2009) [#12]
well, just think also on the data control this could introduce:
Type MyClass
   Field _Mof2Value:int 'private
   Property MultipleOf2Value:Int()
      Set(Value:int)
         ?debug
            if value mod 2 <>0 then throw "Error in game logic, value has to be a multiply of 2!!"
         ?
         _Mof2 = Value
      EndSet
      Get:int()
         Return _Mof2
      EndGet
   EndProperty
End Type



_Skully(Posted 2009) [#13]
So you just want to be able to go:

a:MyClass=new MyClass
a.MultipleOf2Value.Set(2)
Print a.MultipleOf2Value.Get()


Rather than having separate methods for them such as
Method MultipleOf2Value_Set(val:int)
   _Mof2Value=int
End Method

Method MultipleOf2Value_Get()
   return _Mof2Value
End Method



Brucey(Posted 2009) [#14]
So you just want to be able to go:

Except you would be able to write :
a:MyClass=new MyClass
a.MultipleOf2Value = 2
Print a.MultipleOf2Value

and internally those property methods would be called.


plash(Posted 2009) [#15]
So you just want to be able to go
...
Rather than having separate methods for them such as
In a class you might have field names that aren't exactly logical, or might not make sense to the person using it.

Also, what your code proposes is that each field is actually an object instance, that of which numbers are not.

EDIT: While we're on the subject, inline operators would be awesome too :)
SuperStrict

Framework brl.blitz
Import brl.standardio

Type TVec2
	Field m_x:Float, m_y:Float
	
	Method Create:TVec2(x:Float, y:Float)
		m_x = x
		m_y = y
		Return Self
	End Method
	
	Inline +:TVec2(vec:TVec2)
		Return New TVec2.Create(m_x + vec.m_x, m_y + vec.m_y)
	End Inline
End Type

Local vector:TVec2 = New TVec2.Create(10.0, 10.0)
Local vector2:TVec2 = New TVec2.Create(32.0, 1.0)

Local vector3:TVec2 = vector + vector2


EDIT2: To me Get..End Get and Set..End Set are both ugly.


ziggy(Posted 2009) [#16]
EDIT2: To me Get..End Get and Set..End Set are both ugly.
Apart from the look of the get/set syntax, that can be designed to look better (I agree to this point). I *think* Mark is not a big fan of Properties (otherwise he would have implemented them) but I still would love to see this implemented some day.

A old vb-like implementation may look better to you?
Type MyClass
   Property Get Name:String()
      ...
   End Property
   Property Set Name(Vale:String)
      ...
   End Property
End Type
Local Item:MyClass = New MyClass
'Usage example:
Item.Name = "My Name"
Print Item.Name

Implemeting only one of them (only one set or only one get) makes a readonly/writeonly property. I preffer this syntax. It looks much more basic-like.

Anyway, that's only a mixture of a wish and a feature request.


ziggy(Posted 2009) [#17]
It seems this has been requested long time ago in this other thread


_Skully(Posted 2009) [#18]
How about...

Type MyClass
   Field Name:string
       Set(val:string)
          if len(val)>0 Name=Val
       Get()
          return name
   End Field

   Field X
   Field Y
End Type


so Field with nothing is standard... but if you add Set()... the instructions are executed below until Get() is encountered.. Get should automatically return the value if excluded

so...
Type MyClass
   Field Name:string
       Set(val:string)
          if len(val)>0 Name=Val
   End Field

   Field X
   Field Y
End Type


Would also be valid... how 'basic' is that :)


klepto2(Posted 2009) [#19]
As a professional C# developer I'm using properties a lot and it would be really nice to see them in Blitzmax.
Unfortunatly, properties makes no sense in the current reincarnation of Blitzmax.
Properties are there to give an interface to private fields. As long as Blitzmax
just provides full private/full open definition of types there is no need of properties.

So as Brucey already suggested, a better access system should be implemented first and then properties are a good addition.


_Skully(Posted 2009) [#20]
I agree with that as well... in a sense. The two are not mutually exclusive since the Set code could still be valid even if the field itself is not private... if there is an associated Set for a field... throw an error if someone tries to set it manually... in other words, by adding a Set() you automatically make put the field behind bars


ziggy(Posted 2009) [#21]
better access system should be implemented first and then properties are a good addition.
Well I think they are two faces of the same coin. I would love to see this implemented at the same time, if it is ever done.


skidracer(Posted 2009) [#22]
I like BlitzMax because it's compiled and fast.

When I look at an equals sign in C# I expect it to take 30 cycles and have side effects.

All the examples above illustrate is how BlitzMax could be modified to run slower with the additional benefit that you have completely obfuscated the meaning and performance of the = symbol in BASIC.


Corum(Posted 2009) [#23]
I'd also like Private/Protected/Public fields. I think that would be far more useful as an overall language enhancement.

Just this! :)
Without a proper scope management, the Properties feature would be an useless addition.
In the current scenario, even the getter/setter stuff has no much sense, except for the thread-safe benefits and coding style.
With members scope implementation, this nice language would step a little more in the OOP philosophy direction.


Mahan(Posted 2009) [#24]
@skidracer:

All the examples above illustrate is how BlitzMax could be modified to run slower with the additional benefit that you have completely obfuscated the meaning and performance of the = symbol in BASIC.



From an OOP standpoint I don't agree with you. Properties and data protection/hiding provide lots of benefits too:

Example: The possibility to make true immutable instances: If you make a class-function factory (like: Create<typename>(all, init, params, go, here)) and then only provide public read properties, you get an class whos instances are immutable (internal values cannot be changed, once created) and can thus be passed between threads without synchronization. This is a nice design pattern used often in Java (probably .NET too)

Since the only field-accessors are read properties, the compiler will protect you (or anybody else using your class too(!)) from making the mistake of modifying an created instance.


The idea of modern statically typed OOP as found in Java and .NET (and others) today is that the programmer can design classes that are self-providing and by their own definition can guide other programmers how to use them in a correct way.

Another example borrowed from delphi:

The TDatabase (old BDE component) has methods called Open() and Close(). It also has a property called Connected so you can always check if the TDatabase instance is connected to a db like this:

if (db.connected) then
begin
  //whatever
end;


But to simplify matters they also made the same property a replacement for Open() and Close() if you use it as a write-property.

Thus this is perfectly valid:

  db.connected := True; //same as db.Open();

  //or

  db.connected := false; //same as db.Close();



Depending on how it's used this can be used for very readable code.

If you want top-notch performance you usually don't go OOP in the first place. (in the critical parts)

Most developers today settle for an compromise (since the complexity of programs today is, on average, much higher than programs from decades ago): They use OOP to make a general structure of an app, to keep it manageable and get the help of the compiler to enforce object-model policies, and then they add a few optimized functions for the real time critical stuff.

edit: clarifications


ziggy(Posted 2009) [#25]
All the examples above illustrate is how BlitzMax could be modified to run slower with the additional benefit that you have completely obfuscated the meaning and performance of the = symbol in BASIC.

With all my respects, no ofense intended, but this is plain not true! The compiler should execute the Get and Set methods of a property in the same speed as any other method. There's no reason for the compiler generating slower code there! The same for the = operator. Why should BlitzMax be slower when assigning the result of a GetValue() method than when assigning the same, using a much more readable and user friendly syntax, that lots of languages (also compiled ones) are already implementing? This is not just a .net jit compied thing!


Mahan(Posted 2009) [#26]
@Ziggy:

With all my respects, no ofense intended, but this is plain not true! The compiler should execute the Get and Set methods of a property in the same speed as any other method. There's no reason for the compiler generating slower code there!



I'm pretty sure he means that if you hide functionality behind a setter you can get the side-effect that instead of a simple assignment a whole lot is done "behind the scenes".

Consider an the delphi example I provided in my last post:

The "db.connected := true;" - statement will actually attach the component to a DB (which often is through a network), thus this "simple assignment" can take several seconds to complete.

I however agree with you that if you just got a normal setter that just passes the value to an internal field in the class/type this should be very similar in speed to assigning the field-value directly in an optimized compiler.


ziggy(Posted 2009) [#27]
@Mahan: I agree with you 100%. Obviously it is always the users responsibility to make a wise and balanced use of properties when coding. (in the same way as any other implementation on a class!).
I repeat, no ofense was intended, just a way to show why I don't agree with Skid. After being several years coding in modern OO languages, I can't see a reason to not have this on BlitzMax, unless it is too hard to implement or too complex in the compiler side.


Mahan(Posted 2009) [#28]

I repeat, no ofense was intended, just a way to show why I don't agree with Skid.



I don't think you have to be to scared about offending anyone. Most ppl here are quite professional in that hard evidence is king. If needed we can easily make some good timing examples to show how much time we might loose if we use properties.

We could for example use FreePascal which is a good and free static compiler (without any JiT functionality), which supports Delphi style properties, to make a valid timing example.


Mahan(Posted 2009) [#29]
Ok i wrote a test program in fpc to check this and i got some results:

First run (o1 default low optimizations):
Timing test. Comparission between different field assignment techniques in fpc.
First out : Direct assignment to field. Loop from 0 to 2147483647
Time: 5858

Next out : Assignment through Object Pascal direct-property (no real setter but
reference to field). Loop from 0 to 2147483647
Time: 5952

Finally : Assignment through Object Pascal direct-property through setter method
. Loop from 0 to 2147483647
Time: 20485

Press [enter] to end.


Second run (O3 highest optimizations):
Timing test. Comparission between different field assignment techniques in fpc.
First out : Direct assignment to field. Loop from 0 to 2147483647
Time: 1812

Next out : Assignment through Object Pascal direct-property (no real setter but
reference to field). Loop from 0 to 2147483647
Time: 1686

Finally : Assignment through Object Pascal direct-property through setter method
. Loop from 0 to 2147483647
Time: 5922

Press [enter] to end.



Here is the testprogram code (compiles in Lazarus 0.9.26.2):
prop_speedtest.lpr:


This example goes to show how fantastic properties are in ObjectPascal.

If BlitzMax goes the property road i strongly recommend trying to mimic the ObjectPascal technique since it provides the encapsulation power without almost any penalty in the "direct case" while at the same time allows for getter/setter extensions afterwards without even altering the classes interface to the rest of the program (Note how TDirectProperty and TGetSetProperty has the same exact access syntax).

my two cents. :-)


ziggy(Posted 2009) [#30]
@Mahan: Thanks for this sample. Anyway, don't you think it would be also interesting to compare a method call with a property get or set? Just a suggestion, I don't have free pascal here.


Mahan(Posted 2009) [#31]
Ok ziggy, I added the direct-through-setter assignment but as I suspected it's almost identical to the setter-through-property timing.

Anyways here it goes:

O1 (default) version
Timing test. Comparission between different field assignment techniques in fpc.
First out : Direct assignment to field. Loop from 0 to 2147483647
Time: 5781

Next out : Assignment through Object Pascal direct-property (no real setter but
reference to field). Loop from 0 to 2147483647
Time: 5937

Third run : Assignment directly through Setter. Loop from 0 to 2147483647
Time: 20500

Finally : Assignment through Object Pascal direct-property through setter method
. Loop from 0 to 2147483647
Time: 20483

Press [enter] to end.



O3 max optimization version:
Timing test. Comparission between different field assignment techniques in fpc.
First out : Direct assignment to field. Loop from 0 to 2147483647
Time: 1796

Next out : Assignment through Object Pascal direct-property (no real setter but
reference to field). Loop from 0 to 2147483647
Time: 1686

Third run : Assignment directly through Setter. Loop from 0 to 2147483647
Time: 5922

Finally : Assignment through Object Pascal direct-property through setter method
. Loop from 0 to 2147483647
Time: 5062

Press [enter] to end.


Code for new version:



Gabriel(Posted 2009) [#32]
All the examples above illustrate is how BlitzMax could be modified to run slower with the additional benefit that you have completely obfuscated the meaning and performance of the = symbol in BASIC.


You forgot the additional benefit that - when debugging a project with 300,000 lines - you don't spend two days searching around to see which one of the numerous times you access a particular variable (across numerous namespaces, types and include files) is the needle in a haystack that's actually breaking your application. Instead of just dropping a couple of debug lines into the setter and spotting it immediately.

It's not as though any of this is mandatory. If you don't overload operators, and you don't write setters and getters, everything is as fast and bug-friendly as you want it to be. As Ziggy points out, it's up to the user to use the tools available wisely.


_Skully(Posted 2009) [#33]
There is also a point of compiler optimization here that would take into account fields with and without getter/setters... Mark is all about optimization so I doubt any impact would be felt at all... just different code to handle getter/setter fields vs standard public fields


Mahan(Posted 2009) [#34]
@Skully: That was more or less my most important point in my timing examples - FreePascal has shown how you can have direct properties that are the same speed as going directly to the field.

Observe how this is still a fully valid property with all the same compile-time checking that all properties in Pascal get.

Using this technique you can (just like FreePascal) have properties that don't affect the speed of the runtime at all.


ziggy(Posted 2009) [#35]
I'm so tired of GetValue() SetValue() and also having a visible public _Value field (tree class items for a single task). This does not look very elegant, and makes the code a bit harder to mantain. If classes do expose a real collection of functions, methods, properties and fields, hiding anything that should not be modified from outside the class, you know you can use all the functionality freely, modify the values freely, and this makes coding much more elegant, easier and more reliable IMHO. Encapsulation is your friend! :D

@Mahan: Great demo. :D


_Skully(Posted 2009) [#36]
I think everyone agrees that public/private would be sweet in types... #1 in my books...

Honestly I don't care that much about Getters and Setters... I just create Methods to do that

Type This
field that:int

   Method Set_That(val:int)
      ...
   end Method
end type

But I do appreciate the elegance gained by them from other languages


TaskMaster(Posted 2009) [#37]
I agree that this automatic getter setter thing would be great.

Here is the issue as I see it.

You make a type and in the first couple of version, you do not have to protect the x field, so you just allow it to be directly accessed. But then, later, you make a change that makes a change in x affect a new field y. Now, you have to create a SetX and every piece of code you have written that directly accesses x is now broken.

So, your choice is either to make this change and let everybody who uses your type deal with fixing it, or you can make Getter and Setters from the very beginning, even though you don't need them yet.

But, with the change as ziggy suggests it, then you always have a hidden getter and setter. The great thing is the compiler can do some good work for you. If you do not create a getter, the compile can make it a direct assignment and you lose no speed. But, if later you need a getter, then the compiler takes care of that for you as well. It takes no change in syntax on the users part, but now you can make y rely on changes of x. So, you only get the slowdown when necessary and you do not screw with your users making them change their program.