Daisy Chains

Monkey Forums/Monkey Programming/Daisy Chains

Belimoth(Posted 2012) [#1]
Class Daisy
	Field name:String
	Field a:Int, b:Int, c:Int
	
	Method New(name:String)
		Self.name = name
	End
	
	Function Create:Daisy(name:String = "defualt")
		Return New Daisy(name)
	End
	
	Method A:Daisy(a:Int)
		Self.a = a
		Return self
	End
	
	Method B:Daisy(b:Int)
		Self.b = b
		Return self
	End
	
	Method C:Daisy(c:Int)
		Self.c = c
		Return self
	End
	
	Method ToString:String()
		Return name + ": " + a + ", " + b + ", " + c
	End
End

Function Main:Int()
	Local daisyChain := Daisy.Create("foo").A(1).C(2).B(3)
	Print daisyChain.ToString()
	Return 0
End


It would be nice to be able to format it like this:
Local daisyChain := Daisy.Create("foo")
			 .A(1)
			 .C(2)
			 .B(3)


Could it be done with modified parsing? Or is it just not feasible in a language without mandatory ';' at the end of each line.


Nobuyuki(Posted 2012) [#2]
If I'm not mistaken, VB.net's syntax allows you to do this, but it has to be in a special code block, which is signified by With..End With. It would look something like this:

Dim daisyChain as New Daisy("foo")
With daisyChain
    .A(1)
    .B(2)
    .C(3)
End With


Monkey's line termination is done similar to VB (complete with line continuation character and line concatenation character, with similar limitations to both). I thought a With keyword would be nice, but in practice, it's just syntactic sugar.

If Ted / Jungle had scriptable snippets we could paste in, that would be a decent workaround for both this, and a lot of other "problems" of convenience.

However, in your example class, the syntax could be simplified with a little better use of the New constructor (which can be overloaded). Adding different method signatures, ie: a default constructor, which initializes name with "default" instead of having a Create function, and another constructor with optional arguments for A, B, and C.

Depending on the size of your class, you can have many different types of overloads for construction, putting the arguments of least importance at the end. Objects which would cause null references that you'd want default values for can go in an overloaded ctor, etc. For example:

[monkeycode]
Class Crap
'These are fields that default init to 0 because they're type prims.
Field A%, B%, C%
'Pretend these are objects of yours that need to be initialized to be used
Field Important:Object, NonImportant:Object

'Default ctor
Method New()
Important = New Object("Some reasonable construction args")
NonImportant = New Object()

A = 1 ; B = 2 ; C = 3
End Method

'Method where NonImportant isn't specified; A, B, and can be defaulted
Method New(Important:Object, A%=1, B%=2, C%=3)
NonImportant = New Object()

'Set instance fields to argument values
Self.Important = Important
Self.A = A ; Self.B = B ; Self.C = C
End Method

'Method where NonImportant is specified; it cannot be defaulted because
'objects can't be initialized within a method definition by design
Method New(Important:Object, NonImportant:Object, A%=1, B%=2, C%=3)
Self.Important = Important
Self.NonImportant = NonImportant
Self.A = A ; Self.B = B ; Self.C = C
End Method
End Class
[/monkeycode]

Hope this helps.


Belimoth(Posted 2012) [#3]
That is all good information :) That is the strategy I will fall back on for simpler classes, but the one I am working has many optional properties and different ways to initialize them. The chaining works on one line, it is just dense.

Monkey doesn't have a dedicated continuation character, does it?
At the very least I wish '.' was treated as an operator for tokenization purposes so I could do:
Local daisyChain := Daisy.Create("foo").
			 A(1).
			 C(2).
			 B(3)



Nobuyuki(Posted 2012) [#4]
Monkey should continue a line if the last character in a line is an operator (excluding the semicolon, the line concat char) or some other chars. For example, "+" "," , and "(" are all valid.

More info:

http://www.monkeycoder.co.nz/Community/posts.php?topic=3414