Jump to content

Overloading Papyrus Functions


Recommended Posts

Is there a correct/recommended way to overload a non-native script function in Papyrus?

 

As an example, I have a script with the function Instantiate that exposes this signature:

Bool Function Instantiate (ObjectReference objBase)

Normally, I would pass to this function a single object reference, however, I find that I would like to also pass a list of references to it as a FormList.

 

Would the best way be to declare the function again, with FormList as a parameter?

Bool Function Instantiate (FormList flstBase)

Or to have internal logic to differentiate between parameters passed?

Bool Function Instantiate (form frmBase)
	If frmBase as FormList
		;handle form list argument
	ElseIf frmBase as ObjectReference
		;handle obj ref argument

I suppose this latter approach is the only option if Papyrus doesn't allow function overloading natively.

 

Anyone?

Link to comment
Share on other sites

Well, the script won't compile using the first approach.

Script function instantiate already defined in the same state

So it appears that only the second approach is viable.

 

Still very open to suggestions.

Link to comment
Share on other sites

I would do separate things inside the function depending upon the type of form. Unless the forms within the formlist are all the same type as the single objects (i.e. ObjectReference). In which case, I would read into the formlist and pass the individual items into the function thus leaving the function with a single defined process.

 

It all depends on how bad the timing turns out. If it has no issue under a fairly stressful game, then I leave it the way it is. If it chokes up under stress, then I figure something else out. I think the goal is to not overload papyrus, but I've a feeling that your meaning for overload is different than mine.

Link to comment
Share on other sites

Yes. I am using the term "overload" in the OO sense, where a single function can have different implementations depending on the argument type(s). Overloading is a specific case of polymorphism. I am NOT talking about overwhelming the script engine.

 

It appears that native papyrus functions such as RemoveItem can do this (accepting a base Form, an ObjectReference, or a FormList for the first parameter). Also some mathematical operators return integers or floats depending on the argument values.

Function RemoveItem(Form akItemToRemove, int aiCount = 1, bool abSilent = false, ObjectReference akOtherContainer = None) native
i = 29 / 6       ;returns 4
f = 29.0 / 6.0   ;returns 4.83333

Anyway, from what I can tell through experimentation, Papyrus does not allow me to create polymorphic functions.

 

So if I want this behavior, I have to either fake it with something like this:

Bool Function Instantiate (form frmBase)
	If frmBase as FormList
		;handle form list argument
		return InstantiateFromFormList(frmBase as FormList)
	ElseIf frmBase as ObjectReference
		;handle obj ref argument;initialize the object for positioning
		return InstantiateFromObjectRef(frmBase as ObjectReference)
	EndIf
;create references to associated objects
;returns True if successful, False on fail
EndFunction

Bool Function InstantiateFromObjectRef(ObjectReference objBase)
;instantiate from ObjectReference
EndFunction

Bool Function InstantiateFromFormList(formList flstBase)
;instantiate from FormList
End Function

Or, probably better, just create a separate function and not try to have this type of polymorphic behavior.

Bool Function Instantiate (ObjectReference objBase)
;original function signature
EndFunction


Bool Function InstantiateFromFormList(formList flstBase)
;similar but distinct function to instantiate from FormList
End Function

Pity.

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

As far as I know, you can't do what I would call 'true' overloading in Papyrus. However, you can force the issue by defining parameter defaults, similar to what you found in the RemoveItem function header:

Function MyOverLoadedFunc(ObjectReference objBase = None, FormList flstBase = None)
    
    if objBase != None
        ; do stuff
    endIf

    if flstBase != None
        ; do stuff
    endIf

EndFunction

Then you could call it like this:

MyOverLoadedFunc(objBaseRef) ; if given only one parameter, compiler assumes first parameter is given

OR

MyOverLoadedFunc(flstBase = flstBaseRef) ; we must specify which parameter, otherwise compiler assumes first parm

But... just because you can, doesn't mean you should. At that point you are better off with two nice and simple functions with descriptive names, with the function that takes a FormList calling the function that takes an ObjectReference in a loop, so as not to duplicate code. Function parameter defaults seem to be intended for simplifying function calls by providing default values for trivial parameters, not 'overloading' per se.

The conditional logic in my example which checks for which parameter is passed in also defeats the purpose of overloading in the first place (as you know, truly overloaded calls would get resolved at compile time, not runtime) and invites bugs to happen. For example, what if BOTH parameters are passed in or what if neither parameter is passed in? The function would either have to do nothing or generate some sort of error and both of those scenarios are bad and can be completely avoided by not designing the function that way.

My next statement is not meant to be offensive, just constructively critical. Your example of casting the parameter in an attempt to identify it is an even worse anti-pattern than the one I gave, so I'm glad you decided against it. It also invites bugs to happen because you lose the inherent type-safety you get from a normal function header designed to take just one specific data type. Essentially, you've now opened the door for any type of form to get passed into your function, which could result in very odd bugs that show up in testing, but with code that compiled just fine. If you ever find yourself writing conditional logic to guess what data type something is in a strongly-typed language, that almost always indicates that you have a bad design :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...