ID:1838831
 
Applies to:DM Language
Status: Open

Issue hasn't been assigned a status value.
Wikipedia Article: http://en.wikipedia.org/wiki/Method_chaining

I don't know how feasible this is, but I'd very much appreciate this..


Example:
/obj/explosive
proc/Explode()


new /obj/explosive(loc).Explode()


instead of

var/obj/explosive/explosive = new(loc)
explosive.Explode()


--

I guess you could do this in this example

/obj/explosive
var/explode_on_creation = 0

proc/Explode()

new /obj/explosive(loc){explode_on_creation = 1}


but I think the method chaining would work better IN THIS EXAMPLE.

---

Another example:
/mob/person
var/name
var/age

proc/SetName(name)
proc/SetAge(age)

var/mob/person/p = new(loc).SetName("John").SetAge(20)

etc.
I think this is the same limitation thats stopping id:1313313 from working, really.

Otherwise, if that were fixed, there'd be nothing stopping you from implementing your own chaining like:

mob/Login()
var/obj/g = new(loc):setVar("desc","poop"):setName("guy")

obj
proc
hi()
world << "[src]: hello world!"
return src
setVar(prop,val)
vars[prop] = val
return src
setName(n)
name = n
return src

The lack of method chaining is probably what I dislike the most about the syntax of DM. I think this kind of syntactic sugar is expected from a language as high-level as DM, and I like having syntactic sugar. I would approve of any feature that makes the language more fluent.

I don't doubt that there would be fools who would misuse method chaining, by needlessly calling the same functions over and over again, but that shouldn't be a reason not to implement this feature. This would make prototyping things a whole lot easier.

The obstacle that's blocking this feature right now is that there is an unresolved conflict between a few different operators, which is confusing the compiler. The conflicts seem to get even worse when dealing with preprocessor macros.
Currently I've gotten into the habit of separating methods from objects and keeping these methods global. However, it does allow for a backwards sort of "method chaining" but is really just nested function calls.
object
var/x
var/y

proc/object_create(X=0,Y=0)
var/object/o = new()
o.x = X
o.y = Y
return o

proc/object_set(object/O, X=0, Y=0)
O.x = X
O.y = Y
return O

proc/object_to_string(object/O)
return "([O.x],[O.y])"


// Assuming calling from world/New() or client/New()
// Arbitrary entry point.
proc/main()
world << object_to_string(object_set(object_create(),10,20))
// "(10,20)"
In response to Multiverse7
Yeah, you basically end up with overly complicated sequences of variable definitions until you get to the method you want but if you've been programming DM for ages you just get used to it which is probably why it's never been a feature.
There are basically two things holding me back, neither of which I think is necessarily insurmountable: the parser and the fact that this can't work with the : operator. (Also with the . operator, procs have no return type so . would have to be interpreted as : for this to work.)

With the : operator also being used for ternary expressions, there is a chance changing this could impact existing code.

The parser is an issue because changing the order of operations is not trivial. Adding functions is easy enough, and I just recently added a whole new type of statement, but none of that messes with operator precedence.

Nevertheless I think this would be a nice thing to have, and the risk of changing existing code is fairly low. It's just something I haven't thrown a lot of time into. (I'd also dearly love an operator like Dart's .., which chains off of the original value instead of the proc's return value, but I think that'd be much harder to parse.)
Well how feasible is it to add onto the compiler so that procs return their value?
If you mean procs specifying a return type, not very. If you mean ignoring type and treating . like : and allowing both to be used immediately after [] and (), that I'm not sure of.
Well I'd think it'd make for a lot of compacter code and especially useful for arrays.
This would be very useful but also other languages allow chaining based off not just the return value but they allow you to specify values upon creation such as like below.

new/obj With{.VariableName="value",.Variable2="value2"}


and etc. This chains it to the original value, and the other way as above(previous post) chains it to the return value.

Chaining to the original value though it'd only be possible to set the variables, but not call procs
In response to Superbike32
It's not well documented, but as seen on the reference page for newlist(), we kind of already have that. It's called "modified types", although the name is kind of misleading because you can't actually modify a type. I think it would make more sense to call them "custom initializations".
In response to Multiverse7
They really are modified types:
mob
Login()
var modified = /obj { name = "Poop" }
src << new modified
src << new /obj
src << new modified

/*
Output:
Poop
obj
Poop
*/

Sadly, values for modified types only allow constants.

Your "custom initialization" is really just shorthand for:
var obj/thing = new
thing.varA = a
thing.varB = b


Lummox JR mentioned Dart's .. operator, which in DM would get rid of the need for declaring a new "thing" variable, and would look something like this:
new /obj
..varA = a
..varB = b
In response to Kaiochao
Kaiochao wrote:
They really are modified types.

I'm sure that's all basically just metadata used by the compiler. What I should have said was that you can't actually modify types at runtime. However, I wasn't sure if references to "modified types" could actually be saved in a var like an instance, so that is interesting.

Sadly, values for modified types only allow constants.

I doubt that they could ever allow anything other than constants, although I should point out that some of the settings for proc or verb types can actually be modified at runtime, but those "types" are probably very different from object types.

Lummox JR mentioned Dart's .. operator, which in DM would get rid of the need for declaring a new "thing" variable, and would look something like this:
new /obj
..varA = a
..varB = b

Internally, that's still set to a variable. The difference is that you can't directly access it, and you made the code less readable and modular.
I didn't know that was possible before but your saying you wouldn't be able to do code like below?

var/State=1
if(Level>9)
State++
if(Level>24)
State++
if(Level>39)
State++
if(Level>54)
State++
new /obj{icon_state="Object[State]"}


You could initialize icon_state with "Object1" directly but not use the variable for [State], am I right in how that works?
In response to Superbike32
Yes.
In response to Superbike32
Superbike32 wrote:
I didn't know that was possible before but your saying you wouldn't be able to do code like below?

 var/State=1
if(Level>9)
State++
if(Level>24)
State++
if(Level>39)
State++
if(Level>54)
State++
new /obj{icon_state="Object[State]"}


You could initialize icon_state with "Object1" directly but not use the variable for [State], am I right in how that works?

This would throw a "expected constant expression" error.
I don't know if Dart's .. operator works to chain var assignments like that anyway. I've only seen it done with functions, like:

Sound s = new Sound()..Load(filename)..Play()

I don't think this makes the code less readable, as long as you know what the operator does. And modularity doesn't apply. I think this kind of thing would be potentially cool, although it's not currently on my radar.
What would be the difference between that and the requested function chaining using the . operator? Unless this chains off of the original value where-as the . operator should chain off of the return value.

Although I do propose that we should be allowed to use modified types with expressions that aren't constant.

What was the limitation in place that stopped from allowing expressions with variables in them?
In response to Lummox JR
That's a much better example, although it seems like making the parser recognize that format would be a nightmare.
In response to Superbike32
Superbike32 wrote:
Although I do propose that we should be allowed to use modified types with expressions that aren't constant.

That isn't possible, because a modified type is really just another type. Types are defined at compile-time, not at runtime, so that wouldn't work.

That's not to say it's strictly impossible for the future, but the idea of creating new types at runtime doesn't sound all that useful. All anyone would really want this for is an initializer, which is a job for New() or another proc.
Page: 1 2