extending Property syntax

Monkey Forums/Monkey Programming/extending Property syntax

Nobuyuki(Posted 2012) [#1]
hello. While looking at some recent threads on arrays, I noticed that a lot of people have problems at first dealing with initializing them, and understanding the behavior and syntax of higher dimension arrays. Muddy_shoes wrote an interesting class to return an initialized 2d array, but the syntax can be a bit awkward and I was thinking of perhaps taking it one step further and making my own Array2D/Array3D container classes.

When thinking about this, however, I soon realized that Monkey properties have a number of limitations that make this difficult, if not impossible to implement in the expected fashion. Two of the things that would be a lot more helpful to simplify the syntax would be if Monkey could support multiple arguments in a property, and were also able to support default properties.

Now, I know the latter sounds like a bad idea at first to anyone who remembers the pain of VB6 syntax, but since then, the syntax of default properties have changed such that there are no longer any ambiguities when it comes to setting an object reference -- default properties in VB.NET require at least one argument, and have a special keyword attached to the property in the class. There's a few MSDN articles on the subject; I will link one to show how it's done in modern VB, and then one to show how it's changed from VB6 and why it's better now.

http://msdn.microsoft.com/en-us/library/se6z814t.aspx
http://msdn.microsoft.com/en-us/library/h7bfkxc1%28v=vs.90%29.aspx

While default properties may not sound like it would be very useful to make code easier to read (in fact, it could easily do the opposite), it is ideal for simplifying the syntax of container classes such as a hypothetical Array container. Here are two pseudocode examples of what difference it could make.

[monkeycode]
Class Array2d < T >
Private
Field a:T[][] 'Internal array

Public
Method New(x:Int, y:Int)
'do init stuff here
End Method

'Right now, these properties are not valid monkey code, because Properties cannot
'Take more than one argument, and the syntax can lead to getter/setter ambiguities.
'See post for potential workarounds

Method Cell:T(x:Int, y:Int) Property 'Get
Return a[x][y]
End Method

Method Cell:Void(value:T, x:Int, y:Int) Property 'Set
a[x][y] = value
End Method
End Class


Function Main:Int()
'Usage
Local MyArray:Array2d<String> = New Array2d<String>(5, 3)

MyArray.Cell(2, 2) = "The data at (2,2)."
Print MyArray.Cell(2, 2) 'Should return the proper stuff
End Function
[/monkeycode]

And now, here's what the code might look like with the Default keyword being able to define a property:


[monkeycode]
Class Array2d < T >
Private
Field a:T[][] 'Internal array

Public
Method New(x:Int, y:Int)
'do init stuff here
End Method

'Right now, these properties are not valid monkey code, because Properties cannot
'Take more than one argument, and the syntax can lead to getter/setter ambiguities.
'See post for potential workarounds

Method Cell:T(x:Int, y:Int) Default Property 'Get
Return a[x][y]
End Method

Method Cell:Void(value:T, x:Int, y:Int) Default Property 'Set
a[x][y] = value
End Method
End Class


Function Main:Int()
'Usage
Local MyArray:Array2d<String> = New Array2d<String>(5, 3)

MyArray(2, 2) = "The data at (2,2)."
Print MyArray(2, 2) 'The code in the other example should also work
End Function
[/monkeycode]

At first, I thought having a default property would be the only thing keeping the second code example from being able to work, but of course, Monkey properties are unable to handle multiple arguments for its getter and setters. Some ways to work around this would be to always assume the property of type Void is the setter, and to always assume the first argument is the "value" (or require the setter value to be always named "value"; this may or may not require reserving the word, which of course could break existing code). Another potential workaround would be to reserve Get/Set (or Getter/Setter) keywords or change the property syntax -- this could also break existing code.

Properties seem like they were a rather late, though welcome, addition to the Monkey language. I'd think it would be really nice if they could be extended to support a few more things, however. What do you guys think?


AdamRedwoods(Posted 2012) [#2]
I'm for the multi-param property.

For defaults, it seems like a great idea, but i don't want things to become harder to debug, but I can't think of a situation where it would be confusing to debug.


Rone(Posted 2012) [#3]
I would like to see that the types can define indexers.

Method Self:T[x,y] Property  'Get
     Return a[x][y]
End 

Overall, monkeys property syntax looks mounted somewhat later...
An .Net like syntax would be cleaner and more flexible, I think
Field _test$ = "test"

Property MyProperty$
   Get
	return _test
   Set
	_test = value
End  

And the equivalent auto property
Property MyProperty$ = "test"

And extern
Extern
...
Property MyProperty$
   Get = "GetMyProperty"
   Set = "SetMyProperty"
End  


Especially auto-properties were great because they would save one a lot of tip work


Tibit(Posted 2012) [#4]
@Rone, I agree I really want auto properties to. I have brought this up several times.

So instead of just saying it is good do you have good motivational code-examples of when auto properties would be useful, simplify, improve code, and so on?

On syntax level I suggest something like this for auto properties:
[monkeycode]
Field Fuel:Int Property Get Set '(compile error if field is private)
[/monkeycode]


Rone(Posted 2012) [#5]
- syntactic sugar for your convenience when a lot of getters and setters are needed....Potentially, it also saves you time.

- helps to not declare public fields, because you're lazy

- prevents errors when you need only getter and setter


zoqfotpik(Posted 2012) [#6]
Can someone either explain properties or point to an explanation? This is not a usage with which I am familiar.


Rone(Posted 2012) [#7]

A property, in some object-oriented programming languages, is a special sort of class member, intermediate between a field (or data member) and a method. Properties are read and written like fields, but property reads and writes are (usually) translated to get and set method calls. The field-like syntax is said to be easier to read and write than lots of method calls, yet the interposition of method calls allows for data validation, active updating (as of GUI visuals), or read-only 'fields'. That is, properties are intermediate between member code (methods) and member data (instance variables) of the class, and properties provide a higher level of encapsulation than public fields.


http://en.wikipedia.org/wiki/Property_(programming)


Nobuyuki(Posted 2012) [#8]
I'm thinking that it probably isn't reasonable to ask for major changes to the monkey syntax, as that could break compatibility or introduce confusion with the language. I feel like it should probably be enough in most case scenarios to extend the syntax for property definitions so that we can do the kinda stuff with them that we're used to in .net, without breaking older code by changing the way how trans interprets the existing syntax.

Default properties, or "auto properties" like you have suggested Rone were available in VB6 and made for horrible ambiguities when it came to reference comparison and assignment. Being from a VB background, I can tell you that I didn't realize how bad an idea they were until seeing how every other language did it. The existing reference assignment and comparison behavior should be maintained, and we should probably avoid any default properties that don't take arguments. Perhaps I don't understand the code example, but it seems like it doesn't take any arguments.

That being said, I'd still like to see default properties implemented a bit, the way .net does it -- but perhaps not as much as I'd like to see properties which take multiple arguments be implemented :)


Rone(Posted 2012) [#9]

...made for horrible ambiguities when it came to reference comparison and assignment.


I can not understand. Do you have an example ..? I use it everyday in c# and had never any problems.

class Test
{
   public bool Enabled { get; set;}
}

just less code, so more clearly
class Test
{
   private bool _enable;

   publi bool Enable
   {
      get
      {
          return _enabled;
      }
      set
      {
          _enabled = value;
      }
   }
}


....but perhaps not as much as I'd like to see properties which take multiple arguments be implemented :)


properties which take multiple arguments, are no properties... per definition. They are called methods ;)
I see the approach you are persecuting, but the clean solution are indexer, I think...
http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
http://en.wikipedia.org/wiki/Indexer_(programming)


Nobuyuki(Posted 2012) [#10]
@Rone

the subject is discussed in http://msdn.microsoft.com/en-us/library/h7bfkxc1%28v=vs.90%29.aspx under the old VB6 behavior for default properties. Basically, if you are looking to access an instance member without explicitly specifying that member (which is what I'm presuming you mean by "automatic" properties), the syntax with reference comparisons becomes messed up. VB6 handled this by reserving the Set keyword for reference assignment. I don't remember how it did reference comparison, but I assure you it was confusing, because if you had a default property without an extra argument, you could have code like this:

'both of these are Object or Variant
Dim foo 'pretend this has a default property "quux" which returns "OK"; for brevity, not shown here.
Dim bar 'pretend this has a default property "zz" which returns "NG"

Print foo.quux  'returns "OK"
Print foo 'returns "OK"
foo = "Okay"   'Assigns default property, NOT reference.
Print foo.quux 'returns "Okay"

Print bar   'returns "NG"
foo = bar  'Assigns the value of bar.zz to foo.quux, NOT the reference.
Print foo.quux  'returns "NG"

'Now, let's set foo back to normal.
foo = "OK"

If foo = bar then Print "True" else Print "False"  'Prints false.
Set foo = bar 'this is how you set object reference in VB6 / VBA

'Does the following line do reference comparisons, or default property comparisons?
If foo = bar then Print "True" else Print "False"  


Maybe you can see the problem with default properties which don't take extra arguments with this example..?

I would loathe to see something like this wiggle its way into Monkey, which is why I worded my proposal very carefully so as not to have anyone think I was suggesting it, or have anyone else make the suggestion. It's just a bad idea. OOP was bolted onto VB as a bit of an afterthought; it took compatibility-breaking changes to the language (including its core syntax) to fix the problems VB6 introduced. We wouldn't want something like that happening with Monkey !

properties which take multiple arguments, are no properties... per definition. They are called methods ;)


Basically, when I say I'm looking for a property which takes multiple arguments, I'm looking to overload a method in a property-like way -- with a single getter and setter. The setter would take exactly one extra argument from the getter in its declaration. The way to accessing this kind of property is still syntactically different to a Method -- this is already explained both in my code snippets in my first post, and in the corresponding MSDN articles. Again, I hope I'm not misinterpreting what you're suggesting.


ziggy(Posted 2012) [#11]
properties which take multiple arguments, are no properties... per definition. They are called methods ;)

All properties are methods. That said, abstract complex data structures can beneffit from having properties with parameters. As instance, a key-value pair data structure, can have an "Item" property that gets a name or idex as a parameter and wich value can be read or modified depending on context. That's a common use for properties with parameters. (among others)


Nobuyuki(Posted 2012) [#12]
Okay, I think I figured out what Rone's talking about with "automatic properties".

http://msdn.microsoft.com/en-us/library/dd293589

I can see where this may be useful for externs, perhaps. I'm still not sure where this is useful outside of .NET, though... (reflection is used on property inspectors, which I'm assuming is the main use of making properties this way)

Perhaps another elaboration on its typical usage, and what makes it superior to a Field without the extensibility of a standard Property would help me understand. Monkey doesn't have access level control to properties, sooo......


EDIT: aaaaaaaaaand, here's the article on indexers. I'm new to this concept, so I guess I get to have a read (recommended for anyone else on the adding indexers vs. extending properties debate going on right now):

http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
http://msdn.microsoft.com/en-us/library/4bsztef7 a comparison between indexers and properties


Rone(Posted 2012) [#13]
access level control to properties...

Class Test
Private
	Method IsRunning(val?) Property
	End 
Public 
	Method IsRunning?() Property
	End 
End



Tibit(Posted 2012) [#14]
Ok I'll give another shot in explaining why auto-properties are the best thing since.. well.. indexed properties?

First. Automatic properties are very useful!

If a programmer follows an OOP code style then in most situations Fields should not be public.

If you are not programming with OOP in mind, then I agree they are kinda useless since properties and automatic properties by extension are just OOP syntax sugar.

However if you do proper encapsulation then you want the so called interface of the class to be clean and secure.

By secure I mean that the class has private and public stuff. The interface of the class (with the exception of inheritance) only contains public access. Whatever happens behind-the-scenes are private, and not of concern to anyone using the class.

This means anything public is part of an interface. Before the time of properties proper OOP involves writing a get and set method for members of the class. While it helps with encapsulation it gets messy quickly - and it takes a lot of time to change such an interface.

After properties things changed. Methods is now used mostly for modifying/writing to the class, and properties are used to read from the class. However this is not so in Monkey, because of the lack of auto properties, so we still need tons of Get property methods - like before.

Bottom line:
Auto properties removes A LOT of glue code that is unnecessary. With auto-properties code becomes more readable and encapsulation becomes less of a mess.

Big Note:
1. However auto-properties with public GET and SET are the same as a Field, and are useless.
2. Also properties with private GET but public SET are unexpected - Microsoft recommends against using them in their code standard for C# as an example.
3. Obviously auto-properties with private SET & GET are also useless, since that is the same as a private field.

---> The only thing needed to increase OOP coding in the majority of cases is to have a way to make a Field private SET and public GET. If we call that auto-property, or a GET field, or readonly field, or something else matter less.

I recommend using Field for auto-propterties. Imo this is intuitive:
[monkeycode]Field MyImportantProperty:Int ReadOnly ' Or maybe call it GetOnly, or just Get, or Out, or Property[/monkeycode]
- Can only be used if Field is in public-scope, else compile error
- Field can now only be SET from within the class, however it can be set any number of times (not to be confused with consts or immutable)
- Anyone can read the field
- If the property return an object, then the object can of course be changed even if there is no SET, never heard of any confusion here
- Only syntax pretification. Compiler will create a Field _MyVarProprety:Int and add a public GET method Proptery and a private SET method property that just returns/sets this var - just like normal - no changes required!

This functionality is very simple & intuitive, and should not be confusing at all to either new programmers or older ones - please comment if you do not agree.

PROS
* increases code readability
* makes it easier to write OOP encapsulated code and of course any bugs caused by improper OOP handling are easier to find
* reduces debug time, makes external libraries easier to understand
* makes external libraries easier to use
* allows for sane code-standards and normal naming of variables instead of having a lot of _temp _privateMyVarialdeDoNotTouchOnlyForProprty fields.
* removes code that no one wants, has no need, and is just an artefact of old syntax
CONS (known)
* None?

I do understand Monkey is not a OOP strict language, however can making writing OOP code easier hurt anyone?

OnTopic: extending Property syntax I think is a simple way to make arrays simple, however like mentioned above, maybe using the [] index property like in C# is a more intuitive syntax and more useful?


Tibit(Posted 2012) [#15]
Just wanted to add a Note about C# and auto-properties. Since syntax is different in C#, having get & set private and/or public makes sense - but it does not in Monkey.

Auto-Implemented Properties C#:
http://msdn.microsoft.com/en-us/library/bb383979

How to: Implement a Lightweight Class with Auto-Implemented Properties C#
http://msdn.microsoft.com/en-us/library/bb384054


Nobuyuki(Posted 2012) [#16]
+1 for Tidbit.

I'm wondering about indexers vs default multi-parameter properties. A bunch of people I know are saying that multi-parameter properties are not the way to go about solving these sorts of problems, and while they didn't recommend indexers either (most of them being from a C, and not .NET background), I had the distinct impression that multi-parameter properties are not a popular idea among non-VB coders at all. I'm not even sure how popular the idea of an indexer is, either, but I think it should be an open discussion.

There was this thing thrown out there about true operator overloading being the 'real' answer to this problem, but again I'm wondering if that's just airy CS people talk. I'm just looking for ways functionality can be added to existing object constructs in a way that's simple, straightforward, and reduces necessary code output without complicating the language. That, and offering the ideas up and hoping they're taken into consideration :)