brigadier icon indicating copy to clipboard operation
brigadier copied to clipboard

[Suggestion] Argument class combining name and type

Open Marcono1234 opened this issue 7 years ago • 6 comments

Currently when creating an argument, the name and argument type are not joined in any way. This can lead to errors where the command uses the wrong type when accessing the value.

Therefore it might be good to have a class which combines:

  • The argument name
  • The argument type

Then the same instance of this class can be used when creating the tree and inside the commands. Additionally the methods getting the value from the context would not have to be static anymore, but could be generic, like T getValue(CommandContext<?>). This would make #18 easier as well since the getTypeNameOrDefault method could be non-static and implemented by the base class only.

Example

CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();

Argument<Integer> barArgument = new Argument<>(barArgument, integer());

dispatcher.register(
    literal("foo")
        .then(
            argument(barArgument)
                .executes(c -> {
                    System.out.println("Bar is " + barArgument.getValue(c));
                    return 1;
                })
        )
        .executes(c -> {
            System.out.println("Called foo with no arguments");
            return 1;
        })
);

Marcono1234 avatar Oct 07 '18 00:10 Marcono1234

This is pretty much exactly what I was trying out on my fork.

Pros:

  • Strong type bounds for argument object mappers
  • "Impossible" to accidentally use the wrong type
  • No more need for static methods on each argument type class

Cons:

  • Breaks the "single chain of method calls" pattern by requiring a field definition
  • Adds a bit more generic noise since a non-inferred type is required

Overall I think it's a good change but I'd be interested to see what others think.

tterrag1098 avatar Oct 07 '18 05:10 tterrag1098

I'd personally prefer to be doing context.getArgument(MY_ARGUMENT) instead of MY_ARGUMENT.getValue(context).

kashike avatar Oct 07 '18 15:10 kashike

That's what I add: https://github.com/tterrag1098/brigadier/blob/0247f59a2ef4a9680b85d069e71df4430973774a/src/main/java/com/mojang/brigadier/context/CommandContext.java#L85

tterrag1098 avatar Oct 07 '18 15:10 tterrag1098

@tterrag1098, Argument should probably not extend ArgumentType. In my opinion this is only confusing since when used as such, the name is basically lost / ignored.

And using an enum for BoolArgumentType might be convenient when writing the class, but could be confusing for the user because they expect multiple values and not just a single INSTANCE. What do you others think about that?

Marcono1234 avatar Oct 09 '18 16:10 Marcono1234

It's a common pattern: https://javarevisited.blogspot.com/2012/07/why-enum-singleton-are-better-in-java.html

tterrag1098 avatar Oct 09 '18 16:10 tterrag1098

:+1: for Argument not extending ArgumentType.

kashike avatar Oct 09 '18 19:10 kashike