Suppose we have the following method:
def myMethodWithParameters(param1, def param2, Object param3) {
...
}
What are the differences between using the def keyword and using Object as type for an argument?
What are the differences between using the def keyword and not using any type/keyword for an argument?
What I know so far and does not completely answer the question:
def keyword is used to allow dynamic types.
So you can even put an Object[] in it.
def keyword can be used to make variables available only in current scope instead of globally
Quick link to the docs which do a good job of explaining this:
When defining a method with untyped parameters, you can use def but
it’s not needed, so we tend to omit them. So instead of:
void doSomething(def param1, def param2) { }
Prefer:
void doSomething(param1, param2) { }
But as we mention in the last
section of the document, it’s usually better to type your method
parameters, so as to help with documenting your code, and also help
IDEs for code-completion, or for leveraging the static type checking
or static compilation capabilities of Groovy.
The general rule I follow with Groovy, is:
If you know what type you expect, or return, then put that type in the definition. If you only accept String, add the type to the parameter (the same with returning a value). This goes doubly for methods which form part of your "public" API (ie: if other classes or people are going to be making use of the method).
If it's just internal, or accepts a range of value types, then leave the argument untyped, and let Groovy sort it out...
Related
I tried to use method overloading in some dart code and quickly learned that overloading is not offered in dart.
My questions are: why is it not offered, and what is the recommended alternative? Is there a standard naming convention since methods that do the same thing but with different inputs must have different names?
Is it standard to use named parameters and then check that the caller has supplied enough information to complete the calculation?
Say I have a method that returns how much money someone makes in a year, called yearlyIncome.
In Java, I would create a method like this
double yearlyIncome(double hourlyRate, double hoursWorkedPerYear)
And maybe another method like this
double yearlyIncome(double monthlyRate, int monthsWorkedPerYear)
and so on. They're all used to calculate the same thing, but with different inputs. What's the best, standardized way to do this in dart?
Thanks so much in advance.
Function overloading is not supported in Dart at all.
Function overloading requires static types. Dart at its core is a dynamically typed language.
You can either use different names for the methods or optional named or unnamed parameters
// optional unnamed
void foo(int a, [String b]);
foo(5);
foo(5, 'bar');
// optional named
void foo(int a, {String b});
foo(5);
foo(5, b :'bar');
Optional parameters can also have default values. Optional named and unnamed parameters can not be used together (only one or the other for a single function)
In the case of a constructor you can use named constructors as an alternative
Dart did not support overloading originally because it was a much more dynamic language where the declared types did not have any semantic effect. That made it impossible to use static type based overload resolution.
Dart has since changed to be more statically type, and there is nothing fundamentally preventing Dart from adding overloading today, except that it would be a huge work and a huge change to the language. Or so I'd assume, because there isn't any obvious design that isn't either highly complicated or hugely breaking.
What you do instead in Dart is to use optional parameters. A method like:
String toString([int radix]);
effectively have two signatures: String Function() and String Function(int). It can act at both signatures.
There are definite limits to how far you can go with just optional parameters, because they still need to have exactly one type each, but that is the alternative that Dart currently provides. (Or use different names, but that's not overloading, you can do that in languages with overloading too).
Optional parameters is also one of the complications if we wanted to add overloading to the Dart language - would existing functions with optional parameters would count as multiple overloadings? If you declare a class like:
abstract class WithOverloading {
String toString();
String toString(int radix);
}
is that then the same signature as:
abstract class WithoutOverloading {
String toString([int radix]);
}
Probably not because you can tear off the latter and get one function with an optional parameter, and you might not be able to tear off both functions from the former and combine them into one function. Or maybe you can, that's why it's not a trivial design question how to include overloading into the existing Dart language.
My team's been working with GraphQL Ruby, and we've found use cases for applying scopes and sorting through our queries, and have been writing the same code over and over in several places.
I'm wondering, is there a way to implement resolution logic for a type anywhere it is used? I want to add filtering and sorting arguments on every field that returns a specific type without having to write additional boiler plate whenever I return it from a field. In the example below, I would wrap it with a GraphQL::Function, and the sorting and filtering arguments are passed in on args. I'd like to not have to use the function every time, but just have the type implement the ability to use those arguments for its own resolution.
field :institutionUser, Types::InstitutionUserType do
with_filtering(resolve ->(obj, args, ctx) {
....resolution logic
})
end
It sounds like you want to use a Resolver.
field :institutionUser, resolver: Resolvers::InstitutionUser
...
module Resolvers
class InstitutionUser < GraphQL::Schema::Resolver
type Types::InstitutionUser
def resolve
...resolution logic
end
end
end
https://graphql-ruby.org/fields/resolvers.html
In Grails you can declare a controller action like this:
def create(Integer foo, Integer bar) {
}
And if your HTTP request has parameters named foo and bar with values that can be converted to an Integer, the parameters will be assigned these values. I'm wondering how Grails can do this, because my understanding is that at the JVM bytecode level, a method's formal parameter names are not available. Is this witchcraft or am I misunderstanding something?
Basically what happens is that there's an AST transform that adds a new method with no args and the same name. This new method has logic in it to do the data binding based on the declared types of your "real" method, and then call your method. That's why the types are required (otherwise there's no way to do a conversion) and why you cannot have method overloads.
The inability to have overloaded methods is easy to work around though. Say you wanted an action
def foo(String bar)
and another
def foo(String bar, Integer wahoo)
In this scenario just keep the 2nd method and check to see if wahoo is null.
It's also important to use object parameter types and not primitives. If you use int/long/boolean/etc. and there is no provided parameter, you would get a NPE (since zero is not an acceptable conversion from null for numbers, and either is false for booleans).
You can get a decent sense for what's going on if you decompile the class using JD-GUI or another decompiler.
The fact that Grails controllers are Groovy classes helps quite a lot. Looking through the source code for controllers you can see where it makes heavy use of AST transformations, in particular the MethodNode. So, before it becomes bytecode the "witchcraft" is done. :)
How do we retrieve the list of parameters of a closure/method in groovy dynamically, javascript style through the arguments array
say for example that i want to log a message this way
def closure = {name,id ->
log.debug "Executing method with params name:${} id:${id}"
}
OR
void method (String name,String id) {
log.debug "Executing method with params name:${} id:${id}"
}
I read once about a way to reference the list of parameters of a closure, but i have no recollection of that and looking at the groovy API for Closure reveals only getParametersType() method. As for the method, there is a way to call a method as a closure and then i can retrieve the method parameters
ken
You won't like it (and I hope it's not my bad to do research and to answer), however:
There is no API to access the list of parameters declared in a Groovy Closure or in a Java Method.
I've also looked at related types, including (for Groovy) MetaClass, and sub-types, and types in the org.codehaus.groovy.reflection package, and (for Java) types in the java.lang.reflect package.
Furthermore, I did an extensive Google search to trace extraterrestrials. ;-)
If we need a variable-length list of closure or method arguments, we can use an Object[] array, a List, or varargs as parameters:
def closure = { id, Object... args ->
println id
args.each { println it }
}
closure.call(1, "foo", "bar")
Well, that's the limitations and options!
The parameter names can be retrieved if the compiler included debugging symbols, though not through the standard Java Reflection API.
See this post for an example https://stackoverflow.com/a/2729907/395921
I think you may want to take a look at varargs http://www.javalobby.org/articles/groovy-intro3/
In Groovy types are optional so you can use either:
String foo = "foo"
foo.noSuchMethod()
or
def foo = "foo"
foo.noSuchMethod()
I assumed that the first example would generate a compile-time error, whereas the second would only fail at runtime. However, this doesn't appear to be the case. In my experience, a compile-time error is generated in neither case.
Am I right in assuming then that the only benefit of declaring the type of a reference is as a form of documentation, i.e. to communicate intentions to other programmers. For example, if I write a method such as:
def capitalize(String arg) {
return arg.toUpperCase()
}
This communicates the type of arguments that should be passed to the function much more effectively than:
def capitalize(def arg) {
return arg.toUpperCase()
}
Does the Groovy compiler perform any type-checking when types are specified?
Thanks,
Don
[Edit] Newer versions of Groovy do allow for compile-time static type checking. Code that uses this annotation IS faster than regular run-time Groovy, as many of the dynamic checks are skipped.
As Cesar said, type checking is a run-time process, one of the major reasons that Groovy is slower than Java (not that that's really bad).
You can see why this is, right? Given the dynamic nature of Groovy, it's near-impossible to tell if String has been extended somewhere else in your code to contain a method noSuchMethod(). The same goes for member type-checking, as it's entirely possible to remove a member of one type, and add a member of another type with the same name later in code. It's probably not common, but very possible.
The question is, how much type checking do you really need? You're calling the method, you really should know what arguments it takes, or if the method actually exists. Using compile-time checking to save you the time of looking it up isn't a core usefulness of the compiler.
In Groovy, type checking is done dynamically at runtime. The benefits of variables with type is that you can be sure that it contains the value you expect them to have, otherwise you get a runtime exception that you can catch and do whatever you need to do to handle the exception.
Compile time-checking in Groovy is close to impossible for types. Your example of
String foo = "foo"
foo.noSuchMethod()
Would work beautifully given that previously an instruction was executed along the lines of
String.metaClass.noSuchMethod { -> println "Yes there is such a method"}
One reason you might specify a type is to allow an IDE to help you.
def foo
foo.[ctrl-space]
... won't help you very much
List foo
foo.[ctrl-space]
... might (depending on the IDE) give you a choice of List's methods. Of course, a method that's not one of the choices might be a valid one to use, for the reasons given in other answers.
There are other automated software maintenance operations that benefit from clues about types. For example, refactoring.