Skip to content

Function overloading #7757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: dev/feature
Choose a base branch
from
Open

Function overloading #7757

wants to merge 26 commits into from

Conversation

Efnilite
Copy link
Member

@Efnilite Efnilite commented Mar 30, 2025

Description

Adds function overloading.

Function overloading allows two functions with the same name to be registered, as long as

  • their parameter types differ, or
  • the amount of arguments differ.

An example:

function overloaded(x: int, y: int) :: int:
	return 1

function overloaded(x: int, y: int, z: int) :: int:
	return 2

function overloaded(x: text, y: text) :: int:
	return 3

function overloaded(x: text, y: int, z: int) :: int:
	return 4

FunctionRegistry

Description
To accomplish this, a new FunctionRegistry class has been added, which is only visible to the function package. This holds all signatures and functions by a namespace. A namespace is either the global namespace, for global functions, or a script, in which local functions can be registered.

Functions and signatures are differentiated by a FunctionIdentifier, which holds the function's name and the types of its arguments.

Why are the methods in the Functions class not deprecated?
In the future, I plan on adding function parameter specification by name, e.g. location(x=10,y=10,z=10,world="world"). When that has been added, there will, in my opinion, be enough future-proofing, thus the FunctionRegistry class can replace the Functions class' functionality. Overloaded functions will not be visible to Functions.

Behaviour

When a function has an ambiguous type in one of its arguments, it will attempt to match based on the other arguments.
Therefore, overloaded(1, {_none}) and overloaded({_none}, 2) will still call the correct overloaded, as the function overloaded(int, int) is the only one that can be matched here.

When a function has multiple implementations, and it can't be decided which one to use (due to variables for example), a parse-time error will be thrown.

image

Like other languages, functions cannot be differentiated by return type.


Target Minecraft Versions: any
Requirements: none
Related Issues: #1185, #2993

@Efnilite Efnilite added feature Pull request adding a new feature. functions Related to functions labels Mar 30, 2025
@Efnilite Efnilite requested a review from Copilot March 30, 2025 14:47
@Efnilite Efnilite requested review from a team as code owners March 30, 2025 14:47
@Efnilite Efnilite requested review from UnderscoreTud and sovdeeth and removed request for a team March 30, 2025 14:47
Copilot

This comment was marked as resolved.

@Efnilite Efnilite requested a review from Copilot March 30, 2025 14:50
Copilot

This comment was marked as resolved.

@Efnilite Efnilite added the 2.12 Targeting a 2.12.X version release label Mar 31, 2025
@sovdeeth
Copy link
Member

sovdeeth commented Apr 1, 2025

"Try clarifying the type of the arguments"

How?

@Efnilite
Copy link
Member Author

Efnilite commented Apr 1, 2025

"Try clarifying the type of the arguments"

How?

I was thinking literal type clarification but I guess that's only for literals

@sovdeeth
Copy link
Member

sovdeeth commented Apr 1, 2025

"Try clarifying the type of the arguments"

How?

I was thinking literal type clarification but I guess that's only for literals

You could evaluate at runtime, which could be very flexible but also possibly confusing to users in some cases.
store the candidates and pick at runtime

@Efnilite
Copy link
Member Author

Efnilite commented Apr 2, 2025

I think I prefer a more limited system that errors at parse time over one that may cause runtime errors. Wdyt?

@Burbulinis
Copy link
Contributor

Burbulinis commented Apr 2, 2025

Why not just use ExprValueWithin to clarify the type?

@sovdeeth
Copy link
Member

sovdeeth commented Apr 2, 2025

Why not just use ExprValueWithin to clarify the type?

ahh good point

@Efnilite Efnilite marked this pull request as draft April 2, 2025 23:15
@sverinn
Copy link

sverinn commented Apr 5, 2025

I am really hyped for this one ngl

@Efnilite Efnilite marked this pull request as ready for review April 8, 2025 08:43
@Efnilite Efnilite requested a review from Absolutionism April 8, 2025 14:45
Copy link
Member

@sovdeeth sovdeeth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preliminary review

* @param name The name of the function.
* @param args The arguments of the function.
*/
record FunctionIdentifier(@NotNull String name, boolean local, int minArgCount, Class<?>... args) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rationale behind making this class instead of just using/upgrading Signature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can replace this to use signature in the pr for named function arguments (fun(x:1,y:2)). changing it now would mean breaking changes for signature now (since hashCode and equals behaviour would differ) and then also for when i add named function arguments, as the methods would then use a different object for arguments/parameters than just Class<?> varargs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would hashcode/equals behavior change due to this PR? Moreover, why would it be a breaking change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently, Signature's hash is only generated based on its name. if we want to be able to have multiple functions with the same name but different arguments, then Signature's hash would have to include these argument types. therefore, someone who is adding Signatures to a set may find that they can suddenly add multiple with the same name, which may not be intended behaviour. this is niche, obviously, but still.

after looking at it further, it seems implementing equals wouldn't lead to any issues, nor would implementing named function arguments be a breaking change.

the problem is that constructing a Signature for getting a function requires single to be known. therefore, you'd need to know whether the function returned a single value before you can search for the function. the same applies to Parameter.

I could make it use Signature, but that'd require just setting the value to false or true.

FunctionIdentifier is basically a representation of the stuff we have available at runtime to find the actual registered Signature. it is therefore an incomplete version of a Signature.

@Efnilite Efnilite requested a review from sovdeeth April 9, 2025 09:30
@Efnilite Efnilite requested a review from sovdeeth April 29, 2025 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.12 Targeting a 2.12.X version release feature Pull request adding a new feature. functions Related to functions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants