{"id":21951578,"url":"https://github.com/toxe/godot-benchmark-multiple-return-values","last_synced_at":"2025-03-22T17:47:09.408Z","repository":{"id":197385730,"uuid":"698288469","full_name":"Toxe/godot-benchmark-multiple-return-values","owner":"Toxe","description":"Godot Benchmark: Returning multiple values from a function in GDScript","archived":false,"fork":false,"pushed_at":"2024-07-24T19:27:02.000Z","size":27,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-03T22:37:57.257Z","etag":null,"topics":["benchmark","gdscript","godot"],"latest_commit_sha":null,"homepage":"","language":"GDScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Toxe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-29T15:18:35.000Z","updated_at":"2024-07-24T20:04:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"32196821-d73a-45c2-bcdd-bf77b72a3ce1","html_url":"https://github.com/Toxe/godot-benchmark-multiple-return-values","commit_stats":null,"previous_names":["toxe/godot-benchmark-multiple-return-values"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toxe%2Fgodot-benchmark-multiple-return-values","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toxe%2Fgodot-benchmark-multiple-return-values/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toxe%2Fgodot-benchmark-multiple-return-values/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toxe%2Fgodot-benchmark-multiple-return-values/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Toxe","download_url":"https://codeload.github.com/Toxe/godot-benchmark-multiple-return-values/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244999230,"owners_count":20544866,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmark","gdscript","godot"],"created_at":"2024-11-29T06:15:06.346Z","updated_at":"2025-03-22T17:47:09.382Z","avatar_url":"https://github.com/Toxe.png","language":"GDScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Godot Benchmark: Returning multiple values from a function in GDScript\n\nI recently wondered what the best way to return multiple values from a function would be. There are proposals but GDScript doesn't support this yet so we have to improvise and out of curiosity I wanted to know which would be the fastest.\n\nI tried returning a class, an array and a dictionary. Sure, I could come with other atrocities but no sane person would actually use these.\n\nSo I made a small project and wrote a benchmark script that you can find below. For each benchmark we run a loop (by default 1000 times) and call a function that returns three values: An int, a Vector2 and a String. We measure how long this takes in microseconds.\n\nFor example:\n\n```swift\nfunc return_dictionary() -\u003e Dictionary:\n    return {\"value\": 42, \"vector\": Vector2(1.0, 2.0), \"text\": \"some fancy text\"}\n\n\nfunc bench_dictionary(iterations: int):\n    for i in iterations:\n        var ret := return_dictionary()\n        var s = \"value: %d, vector: %s, text: \\\"%s\\\"\" % [ret[\"value\"], ret[\"vector\"], ret[\"text\"]]\n        if len(s) != 50:\n            print(\"string should be length %d but is %d instead\" % [50, len(s)])\n```\n\nNote that we don't just measure how long it takes to create and return these values but we also *use* them because a) in a real world scenario you don't just want to return values and forget about them but instead you return them for a reason and using them afterwards is as important for the performance measurement as returning them and b) I make sure that GDScript now or in the future doesn't optimize the call away when the compiler realizes that we don't actually use the return values. Coming from C++ this is always an important part because C++ compilers are usually smarter than you and very happily remove code that actually has no effect.\n\nHere are the results:\n\n![results](images/screenshot.png)\n\n- Returning an array is fastest but the least readable.\n- Returning a dictionary is 10% slower than returning an array.\n- Returning a class is 30% slower than returning an array but the most readable.\n\nThis was from a debug version that I ran from the editor in Godot 4.1.2-rc2. I did export a non-debug Windows version but times didn't differ too much. IIRC returning an array and dictionary was 5% slower and returning a class was 15% slower in the debug version. So not too much of a difference.\n\nAlso note that I was comparing the best times but in reality these fluctuate a lot so in a proper benchmark you should take the median, which I am not doing here.\n\nMain script: https://github.com/Toxe/godot-benchmark-multiple-return-values/blob/master/T03_BenchmarkMultipleReturnValues/main.gd\n\nAlso if you have the urge to click on something *right now:* I exported a web version that you can run here: https://toxe.itch.io/godot-benchmark-multiple-return-values\n\nIf you want to test it yourself you can also do this very fast and easy. Just copy the code below until the UI stuff into one of your scripts and run the benchmarks in for example a `_ready()` function:\n\n```swift\nfunc _ready():\n    print(benchmark(bench_class, 1000))\n    print(benchmark(bench_array, 1000))\n    print(benchmark(bench_dictionary, 1000))\n```\n\nThat's it.\n\nHere is the complete code:\n\n```python\nextends Control\n\n\nfunc benchmark(fn: Callable, iterations: int) -\u003e int:\n    var t0 = Time.get_ticks_usec()\n    fn.call(iterations)\n    var t1 = Time.get_ticks_usec()\n    return t1 - t0\n\n\n# ---- return class benchmark -----------------------------------------------\nclass Results:\n    var value: int\n    var vector: Vector2\n    var text: String\n    func _init(v1: int, v2: Vector2, v3: String):\n        value = v1\n        vector = v2\n        text = v3\n\n\nfunc return_class() -\u003e Results:\n    return Results.new(42, Vector2(1.0, 2.0), \"some fancy text\")\n\n\nfunc bench_class(iterations: int):\n    for i in iterations:\n        var ret := return_class()\n        var s = \"value: %d, vector: %s, text: \\\"%s\\\"\" % [ret.value, ret.vector, ret.text]\n        if len(s) != 50:\n            print(\"string should be length %d but is %d instead\" % [50, len(s)])\n\n\n# ---- return array benchmark -----------------------------------------------\nfunc return_array() -\u003e Array:\n    return [42, Vector2(1.0, 2.0), \"some fancy text\"]\n\n\nfunc bench_array(iterations: int):\n    for i in iterations:\n        var ret := return_array()\n        var s = \"value: %d, vector: %s, text: \\\"%s\\\"\" % [ret[0], ret[1], ret[2]]\n        if len(s) != 50:\n            print(\"string should be length %d but is %d instead\" % [50, len(s)])\n\n\n# ---- return dictionary benchmark ------------------------------------------\nfunc return_dictionary() -\u003e Dictionary:\n    return {\"value\": 42, \"vector\": Vector2(1.0, 2.0), \"text\": \"some fancy text\"}\n\n\nfunc bench_dictionary(iterations: int):\n    for i in iterations:\n        var ret := return_dictionary()\n        var s = \"value: %d, vector: %s, text: \\\"%s\\\"\" % [ret[\"value\"], ret[\"vector\"], ret[\"text\"]]\n        if len(s) != 50:\n            print(\"string should be length %d but is %d instead\" % [50, len(s)])\n\n\n# ---- UI stuff -------------------------------------------------------------\nvar best_class_result := 9223372036854775807\nvar best_array_result := 9223372036854775807\nvar best_dictionary_result := 9223372036854775807\n\n\nfunc run_benchmark_and_update_ui(benchmark_function: Callable, iterations: int, best_result: int, last_result_label: Label, best_result_label: Label) -\u003e int:\n    var t = benchmark(benchmark_function, iterations)\n    last_result_label.text = \"%d μs\" % t\n    if t \u003c best_result:\n        best_result_label.text = \"best: %d μs\" % t\n        best_result = t\n    return best_result\n\n\nfunc _on_benchmark_class_button_pressed():\n    best_class_result = run_benchmark_and_update_ui(bench_class, int(%IterationsLineEdit.text), best_class_result, %ResultsClassLabel, %BestResultClassLabel)\n\n\nfunc _on_benchmark_array_button_pressed():\n    best_array_result = run_benchmark_and_update_ui(bench_array, int(%IterationsLineEdit.text), best_array_result, %ResultsArrayLabel, %BestResultArrayLabel)\n\n\nfunc _on_benchmark_dictionary_button_pressed():\n    best_dictionary_result = run_benchmark_and_update_ui(bench_dictionary, int(%IterationsLineEdit.text), best_dictionary_result, %ResultsDictionaryLabel, %BestResultDictionaryLabel)\n\n\nfunc _on_iterations_line_edit_text_changed(_new_text):\n    best_class_result = 9223372036854775807\n    best_array_result = 9223372036854775807\n    best_dictionary_result = 9223372036854775807\n    %BestResultClassLabel.text = \"\"\n    %BestResultArrayLabel.text = \"\"\n    %BestResultDictionaryLabel.text = \"\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoxe%2Fgodot-benchmark-multiple-return-values","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoxe%2Fgodot-benchmark-multiple-return-values","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoxe%2Fgodot-benchmark-multiple-return-values/lists"}