plee for Properties, Private Fields

BlitzMax Forums/BlitzMax Programming/plee for Properties, Private Fields

Bot Builder(Posted 2006) [#1]
I'm back for a while from my jaunt into .netland.

Anyway, now that I'm coding some blitzmas the main things I miss are private fields and properties.

We've talked about this before, but I'd like to try again.

Now, private fields can be evil, it is true. It's annoying when the field is there, you just can't access it. However, they serve a very good purpose - prevent the user from inadvertently setting the field to an invalid or null value. This will result in an exception somewhere along the line. It might not even show up except in rare circumstances, if the field is not used much.

It is possible to prevent this by peppering your code with if statements checking the value. This is slower and ugly to boot.

If a field is private then it can only be accessed from the class's methods which presumably deal with it in a safe manner. A well written class can guarrantee that the values of its fields will not be out of range.

However, now with all these private fields if you want a reasonably direct method of modifying them, you need to create get/set proxy methods which rather clutter up the class. This is where properties come in. They allow get/set methods to look like fields. Most importantly, the set method can make sure the value of a field is not set to null.

Properties are also useful for things that aren't even fields. For example I might make a 'Rectangle' class and have fields storing position and size. I could have a property "BottomRight", which returns and receives a point class.

My suggestion for a syntax would be:
Property BottomRight
 Method Get:Point()
  return Point.Create(x+w, y+h)
 End Method

 Method Set(val:Point)
  If val <> null Then
   w = val.x - x
   h = val.y - y
  Endif
 End Method
End Property
Converted by blitzmax compiler to:
Method get_BottomRight:Point()
 return Point.Create(x+w, y+h)
End Method

Method set_BottomRight(val:Point)
 If val <> null Then
  w = val.x - x
  h = val.y - y
 Endif
End Method
To use the property:
Print a.BottomRight.X
Converted to:
Print a.get_BottomRight().X
Oh, and constructors with parameters would be nice! To mark: Pretty please? should only take a day or two.

Oh, I almost forgot, it'd be nice to have a "getter" attribute for fields which autocreates a get-only property. Also a 'property' attribute, which for non-base types makes sure it can't be nullable. This cuts down the majority of most get/set method clutter.


Matthew Smith(Posted 2006) [#2]
I'm with you - after using .Net it all makes so much sense and gives your classes (or methods in this case) clarity.

Anyway, time will tell. It's still a great language!!


Dreamora(Posted 2006) [#3]
Second the request for private within classes (not only fields). The actual implementation that is needed makes extending of "information hidding" classes in modules very hard and tricky for users.

As for the properties: would be nice but definitely no must-have.


N(Posted 2006) [#4]
Private/protected fields would be very good. Along with interfaces. And overloading. And generics.


Dreamora(Posted 2006) [#5]
Interfaces? is that somehow different from creating an abstract class?


N(Posted 2006) [#6]
Yes.

An interface is like a 'clean' version of multiple inheritance.

You implement interfaces, and then you can request objects that implement a specific interface. E.g., IRenderable, IStreamable, IContainer, IDisposable, ICloneable, etc.

If you wanted to clone something you would implement the ICloneable class, if you wanted forced disposal of resources you would implement IDisposeable, if you wanted container functionality in an object you would implement the IContainer interface, and so on and so forth.

So yes, it's different.


FlameDuck(Posted 2006) [#7]
I still fail to see the purpose of properties, but private access modifiers and typesafe callbacks (delegates in .Net speak) would be wonderful.


Bot Builder(Posted 2006) [#8]
Yeah, I kind of forgot about interface - they are very nice too. Overloading would be awesome.

Generics, well, generics are very cool. However, they are probably the most difficult things to implement, and they are mainly used to make collections specific.

I think generics would take too much effort on mark's part. Constructors with parameters, private, protected, overloading, interfaces should take a week or so. Perhaps I am optimistic - I don't know how much time mark has in a week, what his usuall per day hourage is.

The only language I've ever messed around with the insides had one of the best structures possible. You could even swap out certain sections of code and get it to compile other languages.

I'd be glad if you could just implement privates, mark

I'd be very glad, maybe exstatic if you could implement all the other stuff as well.

Flameduck:

Consider these two examples, which looks better? Properties are all about syntax sweetness.

a.Speed += 1

a.SetSpeed(a.GetSpeed() + 1)


CS_TBL(Posted 2006) [#9]
a.AddSpeed(1)


-------------------
Method IncreaseSpeed(amount:int)
Speed:+amount
End Method


Koriolis(Posted 2006) [#10]
My proposition regarding properties (already suggested) is much simpler. Why not just treat properties as a pure shortcut for simple getters and setters? This is something I implemented myself in my compiler, and I quite like it.
Type MyType
    Method GetColor%()
        ...
    End Method
    Method SetColor(col%)
        ...
    End Method
End Type

Local obj:MyType = New MyType
obj.color = obj.color / 2 ' or of course, "obj.color :/ 2"

' Identical to 
' obj.SetColor(obj.GetColor() / 2)


Advantages :
- it's crystal clear what you're doing, while using setters and getters obfuscate the code.
- absolutely no unneeded syntax change

Really, that can be added in a blink. I know, I did it.

I still fail to see the purpose of properties
Maybe you just need to use them. As a simple pragmatic point, do you really prefer "obj.SetColor(obj.GetColor() / 2)" over "obj.color :/ 2" ?
If you find the first version more readable then you've managed to surprise me.
As a second more general point, properties are a way to abstratc away data access. You don't care if some value of an object is computed, stored in a field or even fetched from a database, that's really none of your business (as a client).


Dreamora(Posted 2006) [#11]
From the descriptions, Interfaces are the same as abstract types (ie only definition but no implementation).

Interfacing like you mention it and how it is often used is impossible in BM anyway due to the missing support for multiple inheritance :-(


John J.(Posted 2006) [#12]
I really would enjoy it if BlitzMax would some day support properties, method overloading, and operator overloading. Private members would be nice too, although supporting properties and overloading is more useful to me.


N(Posted 2006) [#13]
Interfacing like you mention it and how it is often used is impossible in BM anyway due to the missing support for multiple inheritance :-(


That's why I suggested it. To make it so that it's not impossible. Then again, given that BMax seems to be set in stone now (what happened to enums, eh?), it's probably highly unlikely we'll get anything good out of requests.


Bot Builder(Posted 2006) [#14]
Yes, koriolis's method is best, not even that hard to impelment. This is actually how .net does it - two methods per property and a bit of metadata defining the property.

A practical example of private members is in a class i'm working right now - I've got a Paused field in my main game engine class. However I want the user to use the PAuse() and UnPause() methods because otherwise delta timing will get very messed up as it will think that the amount of time it was paused was one frame, so everything would shoot off in different directions very,very fast. With private fields the user would be forced to use the methods, which would properly reset the delta timing vars. With Properties it would actually look the same way as the user wants it to.


Koriolis(Posted 2006) [#15]
This is actually how .net does it - two methods per property and a bit of metadata defining the property.
And given that BlitzMax doesn't support reflection, metadata doesn't even enter into the equation here. So that really, really couldn't be easier to implement. It's one of those few features that have a very high "usefulness / implementation complexity" ratio. You hack the thing in a blink, and then goes "wow, this little thing is cool".
We just have to convince Mark how much nicer this can make some code look.


N(Posted 2006) [#16]
General idea for properties

i.Speed = 50

If Speed is not a field of i Then
  If i has method SetSpeed Then
    i.SetSpeed( 50 )
  Else
    Throw exception
  EndIf
EndIf

Print i.Speed

If Speed is not a field of i Then
  If i has method GetSpeed Then
    Return i.GetSpeed
  Else
    Throw exception
  EndIf
EndIf


This is exactly how D does it. It's a very simple implementation of properties and works flawlessly. I don't see why it couldn't be added as syntactic sugar for BlitzMax.


Koriolis(Posted 2006) [#17]
If the throw part refers to a compile time error, then that's exactly what I propose.
That's now 3 votes for this implementation. And counting... (I hope)


N(Posted 2006) [#18]
Yes, that would be a compile-time error.


Gabriel(Posted 2006) [#19]
And counting... (I hope)


Make it four. It seems very simple to implement and immensely useful.


Will(Posted 2006) [#20]
Im voting for interfaces. That doesn't just save code space, it makes the structure more flexible for a program.


Leiden(Posted 2006) [#21]
You got my vote!


N(Posted 2006) [#22]
After looking over some stuff, this seems to be exactly how the EachIn functionality is handled. So not adding properties would just be absurd now that I think about it.


Difference(Posted 2006) [#23]
I don't think I get it. You can allready do this:
SuperStrict

Type myt
	Field color:Int
End Type

Local cheese:myt = New myt

cheese.color = 10
Print "Color: " + cheese.color

cheese.color:/ 2
Print "Color: " + cheese.color


Private Fields on the other hand... Yes Mama!


N(Posted 2006) [#24]
Peter: The idea is that you do something while setting the property.

For example, say you do something like i.References = 0

Now, when you do that, i.SetReferences( i% ) is called.

Method SetReferences( i% )
  _refs = i
  If _refs = 0 Then
    Do something
  EndIf
End Method


Or, the parenting situation:
Type Entity
    Field _parent:Entity
    Field _children:TList = New TList
    Field _link:TLink
    
    Method SetParent( p:Entity )
        If _link Then _link.Remove( )
        _link = Null
        _parent = p
        If _parent Then
            _link = _parent._children.AddLast( Self )
        EndIf
    End Method
End Type

Local e1:Entity = New Entity
Local e2:Entity = New Entity
e1.Parent = e2 ' Calls the above code to set the link, remove the old link, etc. - can't do that by just setting _parent



Difference(Posted 2006) [#25]
Thanks! I get it.
It's like VB 6. I allways hated the way those where autocreated, whenever I defined a field, so I hope this is not comming to BMax.
If it's implemented as hidden methods, that I can then overload ( like New() and Delete() ), I guess it's ok, as long as it doesn't impact compilation and execution speed. )


N(Posted 2006) [#26]
Somehow I get the impression you either don't understand what I'm saying or you're wierd as all hell.


Difference(Posted 2006) [#27]
Remind me not to spend more time on you Noel.
It really is exausting how you can turn anything into an insult/conflict.

I don't see anything wierd with what I wrote.


N(Posted 2006) [#28]
Can't take a joke, Pete? O_o


Koriolis(Posted 2006) [#29]
Jokes have to be funny, by definition.


N(Posted 2006) [#30]
It's funny to me, therefore it is a joke.


Leiden(Posted 2006) [#31]
I think its the medication...


Bot Builder(Posted 2006) [#32]
Peter - its not really a replacement for fields, just a syntax sugar for ugly get/set methods. I hope bmax or the C compiler is smart enough to inline alot of the properties though. I know that in C# most of the get properties are inlined by the compiler

I think constructors with parameters would also be very nice. Right now I'm making Create functions, however, these functions are inheritable, and there is no overloading. So I'm limited to only one return type.

Now I have to make "CreatePoint:TPoint" functions.... Plus this means you could call TAtom.CreatePoint:TPoint, which is just plain odd.

[edit] I just realized i could make these functions outside of the classes so they wouldn't looks so bad. Still.


N(Posted 2006) [#33]
Bump.


Bot Builder(Posted 2006) [#34]
Long responses such as this from BRL is why I still use blitz. Oh, wait...

*A bump of optimistic hope*


N(Posted 2006) [#35]
Funny how earlier skidracer said he wanted specific criticism, and then he ignores stuff like this.


Dreamora(Posted 2006) [#36]
Welcome to reality.
Constructive critism is only wanted if it can be done without much work.