Jump to content

About function arguments and being optional


Recommended Posts

I have distributed through my mod function HereIsAFunction( Int argA, Bool argB)--ie., it's called in many places in dialogue fragments.

As the mod has developed, I have seen a great utility in adding another argument, Int argC.

So in my script, I have HereIsAFunction( Int argA, Bool argB = False, Int argC = 0 )

As you may have guessed, where I have called the function using all arguments, the calls run perfectly; and where I have older calls that don't include the third argument, those don't run.

Is there a way to define an argument as optional so that F(A, B, C) will work and F(A, B) will work as well ?

If not, it's no biggie--I'll just fill in the extra arg. But it would be nice to know..

Link to comment
Share on other sites

I do not really get what you're trying to say, you seem, I stress SEEM to be aware of default parameter values if not filled..  so I do not know what to say.. OFC parameter argument loading is possible in most languages, I would suggest perhaps function chaining maybe... where the three parameter one called the two parameter one to handle the other two parameters to keep it nice and clean, however function overloading NOT support in Papyrus, but you can make function chaining work.. this would also mean you do not update to a degree.. OFC I do not know without seeing your code. or with my limited understanding of what you trying achieve and what degree of backward compatibility is required 

To sum up no function parameter overloading is not possible, but function chaining is..    I will make an example BRB

Quick Edit, you may want to make it recursive too, with my limited understanding I have no idea if that is required....  Your function may be void?

Spoiler
ScriptName functionChaining

int a = 10
int b = 20
int c = 30
	
bool Function oneParaemter(int _a = 10)

	if a == _a 
		return True
	endif
	return false
	
EndFunction

bool Function twoParaemter(int _a = 10, int _b = 20)
	bool result 
	if b == _b 
		result = True
	endif
	if a != -a
		result = oneParaemter(_a)
	EndIf
	Return result
	
EndFunction

bool Function threeParaemter(int _a = 10, int _b = 20, int _c = 30)
	bool result 
	if c == _c 
		result = True
	endif
	if a != -a
		result = oneParaemter(_a, -b)
	EndIf
	Return result
	
EndFunction

 

OFC that just example of recursive function chaining, what they can do is only held back by your imagination and skill, my first recursive method at uni had to solve the Fibonacci sequence, I did heaps chaining with byteCode C# and Java, where overloading was allowed and all the function had the same name)), has you notice with Papyrus they have to have different names... 

 

bottom line, all the old code can stay the same, so you do not have to rewrite it and the new code can use whichever loading it wants, which I think, STRESS THINK is what you want?

 

Link to comment
Share on other sites

BTW I wrote the example quickly and yeah, I can see the mistakes, but it not about perfect code, it is about concept of chaining , but knock yourselves out correcting my code, I am first to functionally wise admit  it is wrong)).  but fact that I am not fixing it shows how important that is..

@csbx an example of the code would have been nice 

Edit OK it it bothered me I had to fix it)) 

Spoiler
ScriptName functionChaining

int a = 10
int b = 20
int c = 30
	
bool Function oneParameter(int _a = 10)

	if a == _a 
		return True
	endif
	return false
	
EndFunction

bool Function twoParameter(int _a = 10, int _b = 20)
	bool result = false
	if b == _b 
		result = True
	endif
	Return result && oneParameter(_a)
	
EndFunction

bool Function threeParameter(int _a = 10, int _b = 20, int _c = 30)
	bool result = false
	if c == _c 
		result = True
	endif
	Return result && twoParameter(_a, _b)	
EndFunction

 

 

Link to comment
Share on other sites

Any parameter that has a default value can be skipped unless a later parameter is being given a value.  For example, the base game function RemoveItem is defined as follows:

RemoveItem(Form akItemToRemove, int aiCount = 1, bool abSilent = false, ObjectReference akOtherContainer = None)

If someone just wants to take an item from the player and get rid of it, Player.RemoveItem(theObject, 1) works just fine.  But if they want to take that item and store it in a container, then they must also include a value for the abSilent parameter even if it is the same as the default value, Player.RemoveItem(theObject, 1, false, theContainer)

That said, the question is about custom added functions.  Every use that I have done has had a value passed into each parameter and so I cannot specify with certainty one way or the other.  What I can tell you is that with regards to some SKSE provided functions and events all parameters must be included in the call even if some of them will not actually be used.  This then would lend credence to the requirement to have something for each parameter of a custom function call.

In other words, be safe and go add the third parameter to the older function calls.

Link to comment
Share on other sites

8 hours ago, csbx said:

I have distributed through my mod function HereIsAFunction( Int argA, Bool argB)--ie., it's called in many places in dialogue fragments.

As the mod has developed, I have seen a great utility in adding another argument, Int argC.

So in my script, I have HereIsAFunction( Int argA, Bool argB = False, Int argC = 0 )

As you may have guessed, where I have called the function using all arguments, the calls run perfectly; and where I have older calls that don't include the third argument, those don't run.

Is there a way to define an argument as optional so that F(A, B, C) will work and F(A, B) will work as well ?

If not, it's no biggie--I'll just fill in the extra arg. But it would be nice to know..

First off, yes the way you describe it is exactly how you do the optional parameters.

MyFunction(int A, bool  B = false, int C = 0)    -    this can be called as MyFunction(5) or MyFunction(5, true) or MyFunction(5, true, 1)
Heck you can even make calls like:    MyFunction(A = 5, C = 1)

For example, there is, in Game.psc:

Function DisablePlayerControls(bool abMovement = true, bool abFighting = true, bool abCamSwitch = false, bool abLooking = false, \
  bool abSneaking = false, bool abMenu = true, bool abActivate = true, bool abJournalTabs = false, int aiDisablePOVType = 0) native global

But in C00VilkasTrainingScript.psc, it is invoked as:

Game.DisablePlayerControls(abMovement = false, abMenu = false, abActivate = false, abFighting = true)

 

However, you have to understand that default parameter values are just a coding convenience thing.    In order for the called function to work properly, the calling function has to place on the stack ALL of the needed parameters.   Which is something that gets taken care of by the compiler.     That is, when in the code,   There is a call:    MyFunction(5),   in the compiled version, it is replaced with a binary equivalent of  'MyFunction(5, false, 0)'.     

Now, if MyFunction used to take only 2 parameters,   any code compiled back then will still be placing only 2 parameter values on the stack,  instead of the now expected 3.   Which will cause issues.    What I am getting at, when you change a function signature, you must recompile every single script where that function gets called.   Now, if you have been consistent in your script naming, especially diligent about renaming the TopicInfo script fragments, this should be a fairly easy task.     For example, if I want to find and recompile all scripts for this mod I been working on:
image.thumb.png.df9202712e7b45e531d60a356efded78.png

Link to comment
Share on other sites

Oh, and on the subject of function chaining...    yes, you can do that too.    Suppose you got a really massive mod with thousands of scripts, and a TON of them were compiled  while the function in question took only 2 parameters.    

So you have a MyFunction(int A, bool B = false),  and a ton of scripts  compiled against that signature.    And now you want to have a 3-parameter version.

So you can do this:

Function MyFunction(int A, bool B = false)
	MyNewFunction(A, B)
EndFunction

Function MyNewFunction(int A, bool B = false, int C = 0)
	...
EndFunction

And from any new place, you can call MyNewFunction.

Link to comment
Share on other sites

LOL am I the only one thinking about orphan script in the game save? Sure just adding another parameter will work, but a what cost for existing user?  I am always amazed at what gets baked into the save...

I would advise @csbx to just do it add the parameter and recompile it all, then Version++, and a clean save is required. That the easiest thing to do...  Just be sure  to warn current users a clean save is required, it not the first or the last time we have seen that message..

But like I said, the OP seem to be aware parameters with default values, I think he just wanted some feedback..  

  1. a clean save is required just add a parameter, the easiest options 
  2. function chaining with no re-compiling of existing scripts for backward compatibility for existing users. With a 100 guarantee of no orphan scripts in their game save. Plus I would use Git to keep you honest!!! and to rollback on f*#@ ups))

https://git-scm.com/

 

Link to comment
Share on other sites

5 hours ago, PeterMartyr said:

LOL am I the only one thinking about orphan script in the game save? Sure just adding another parameter will work, but a what cost for existing user?  I am always amazed at what gets baked into the save...

I would advise @csbx to just do it add the parameter and recompile it all, then Version++, and a clean save is required. That the easiest thing to do...  Just be sure  to warn current users a clean save is required, it not the first or the last time we have seen that message..

But like I said, the OP seem to be aware parameters with default values, I think he just wanted some feedback..  

  1. a clean save is required just add a parameter, the easiest options 
  2. function chaining with no re-compiling of existing scripts for backward compatibility for existing users. With a 100 guarantee of no orphan scripts in their game save. Plus I would use Git to keep you honest!!! and to rollback on f*#@ ups))

https://git-scm.com/

 

The mod is unreleased thus far so no issue re: save files. Inevitably there will be such an occasion and so I appreciate that guidance re best practices.

Because I hadn't named my scripts, there's no easy way to swiftly find them that I could see other than text search from a windows folder. There were only 20-25 cases so only 10 minutes of work. Added the additional parameter and re-compiled.

I've never thought about function chaining--that's a cool approach that would be great except perhaps in cases where there's a whack of code you have to duplicate--unless I'm misunderstanding.

@scorrp10 - very clear and fulsome explanation.  I had misunderstood the wiki, thinking you could ignore params in the call if default values were included in the function script. Not quite as simple as that as it turns out. But almost that simple ! Just re-compile !

A sincere thanks to the legends in this thread. A serious education !

Link to comment
Share on other sites

Use sublime and create a Project, then search all the  source files in the  Project folder for HINT not the Game Data Scripts Source folder, for the Function name. But The >>  Project  Scripts Source Folder for the function.

HINT two make sure it compile scripts go the Game Folder, Not the Project Folder

I will do a  screenshot and show you the set up)) BRB BTW if your using MO and MO Folder is Project Folder FYI your Mod live in the Game Folder.. Your Version Control is unnecessary complicated... 

That way Sublime does NOT have read the 15,000 plus  files in the Game to search your Project.  Before I get MO users saying I do this and that and it works, enjoying complicated unnecessary workarounds if it makes you happy..  yeah it not rocket science, I work it out while I was writing this, point Sublime Virtual Game Data Script source and In The Real World to the MO Mod Folder Script Source

I'll be back

Screenshot 2024-05-16 172510.png

@anyone Yes my Projects do not live in the Data Folder, MO users stop kidding yourself. Your Project live in the Virtual Data folder, I have two folders, the Project and In the Game folder, I call It Separation Of Concerns.  Wrye is way more powerful than MO.  You will only fully understand it when you need to create a project..

BIG HINT MO great for playing no so much Projects, where Wrye has 100% support for Projects needs ... I just do this, sync my project and it push new file to the Data folder, and pulls newer project file from data folder (compiled scripts for example) automatically Boom Shaka LA mudda fukker or I do it baby steps for more exquisite control

Next get a Git account and do proper version control of the source files, DO NOT UPLOAD THE FRIGGEN BINARY  PEX FILES... learn to use a gitignore, just upload text files

Another HINT add new files to the Project not the friggen Game..  I AM LOOKING AT YOU MO USERS 

Link to comment
Share on other sites

  • Recently Browsing   0 members

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