Currying Component

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By gau_veldt
:warning: Old Version Published before Godot 3 was released.

Currying is the process of baking some or all arguments to a function call for later use. You can then call a curried function, supplying missing parameters, and the actual call includes the stored arguments, combined with the ones provided when the curried function is called.

We have to abuse PackedScene (and ResourceLoader) to get instances of the Curry object, as will be seen in the SpiceRack test script.

  • Create a new project.

Curry.gd script:

extends Node

#
#  Currying bakes arguments into a function call for later use
#  You can curry some or all of a method's paramters, than
#  provide the remainder at the time of the call.
#
#  One particular use of curry in GDScript is to work around
#  call_deferred's 5-argument limitation.
#

var curry_call=[]
var curry_args=[]

func call_me(arglist):
	if curry_call.size()<2:
		pass
	else:
		var ob=curry_call[0]
		var me=curry_call[1]
		var args=[]
		# add the curried arguments
		for arg in curry_args:
			args.append(arg)
		# add the provided arguments to the curried ones
		for arg in arglist:
			args.append(arg)
		# now do the appropriate Object.call
		ob.callv(me,args)

func curry(ob,me,args):
	curry_call=[ob,me]
	curry_args.clear()
	for arg in args:
		curry_args.append(arg)

func _ready():
	pass
  • Create a Node, call it Curry, extend it (set script) to Curry.gd
  • Save as Curry.tscn

SpiceRack.gd script:

extends Node

onready var Curry=load("Curry.tscn")

func testfunc(a="",b="",c="",d=""):
	print("a=",a,", b=",b,", c=",c,", d=",d)

func somefunc(curried):
	curried.call_me(["passed","as","argument"])

func _ready():
	testfunc("called","normally")
	
	var curry1=Curry.instance()
	curry1.curry(self,"testfunc",["curry"])
	
	var curry2=Curry.instance()
	curry2.curry(self,"testfunc",["another_curry"])

	curry1.call_me(["called","directly"])
	somefunc(curry1)
	
	curry2.call_me(["called","directly"])
	somefunc(curry2)
  • Create a Node, call it SpiceRack, extend it (set script) to SpiceRack.gd
  • Save as SpiceRack.tscn
  • In project settings, set default scene to SpiceRack.tscn

Enjoy!!!

Edit: Removed the inelegant wall of if’s.

Instead of a bunch of ifs, you could use callv which expects an array of arguments.

vnen | 2016-07-15 16:11

Indeed, that works perfectly.

gau_veldt | 2016-07-15 18:00

@vnen Using callv would lift the argument count limit (thus removing the need for the min() clause) too, wouldn’t it?

gau_veldt | 2016-07-15 18:09

Yes, with callv you don’t need to limit the argument count.

vnen | 2016-07-15 19:01