+1 vote

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.

in Engine by (43 points)
edited by

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

Indeed, that works perfectly.

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

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

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.