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.
Related
C# discards prevent allocation of values not needed. Is there something similar in dart? I saw a lot of people use the underscore as if it were a discard, but using two at the same time (like this (_, _) => method() will say the variable _ is already defined.
Dart does allow you to use the same discard operator as C#. You can define a variable or final with a name of _. This works well with the rule avoid-ignoring-return-values (Dart Code Metrics) Importantly, if you name the variable with this, you will not encounter the warning unused-local-variable. However, there is another code rule called no_leading_underscores_for_local_identifiers. You can safely turn this off as long as you don't have someone in your team that has a habit of prefixing variable names with an underscore.
Ignoring the return value
Discarding the return variable
Unfortunately, it doesn't work the same way as C# because it involves an assignment, and you cannot assign two different types to it. You need to declare it as an Object?
I see this recommended in the dart style guide, and copied in tons of tutorials and flutter source.
final foo = config.foo;
I don't understand it, how is this considered best practice when the readability is so poor? I have no clue what foo is here, surely final String foo = config.foo is preferable if we really want to use final?
This seems the equivalent to using var, which many consider a bad practice because it prevents the compiler from spotting errors and is less readable.
Where am I wrong?
In a lot of cases is does not really matter what type you are using as long the specific type can be statically determined by the compiler. When you are using var/final in Dart it is not that Dart does not know the type, it will just figure it out automatically based on the context. But the type must still be defined when the program are compiled so the types will never be dynamic based on runtime behavior. If you want truly dynamic types, you can use the dynamic keyword where you tell Dart "trust me, I know what I am doing with this types".
So types should still be defined where it matter most. This is e.g. for return and argument types for methods and class variables. The common factor for this types is that they are used to define the interface for using the method or class.
But when you are writing code inside a method, you are often not that interested in the specific types of variables used inside the method. Instead the focus should be the logic itself and you can often make it even more clear by using good describing variable names. As long the Dart analyzer can figure out the type, you will get autocomplete from your IDE and you can even still see the specific type from your IDE by e.g. Ctrl+Q in IntelliJ on the variable if you ends up in a situation where you want to know the type.
This is in particular the case when we are talking about the use of generics where it can be really tiresome to write the full specific type. Especially if you are using multiple generics inside each other like e.g. Map<String, List<String>>.
In my experience, Dart is really good to figure out very specific types and will complain loudly if your code cannot be determined statically. In the coming future, Dart will introduce non-null by default, which will make the Dart compiler and analyzer even more powerful since it will make sure your variable cannot be null unless this is something you specifically want and will make sure you are going to test for null when using methods which are specified to not expecting null.
About "Where am I wrong?". Well, a lot of languages have similar feature of var/final like Dart with the same design principle about the type should still be statically determined by a compiler or runtime. And even Java has introducing this feature. As a experienced Java and Dart programmer I have come to the conclusion for myself that typing inside methods are really not that important in a lot of cases as long I can still easily figure out the specific type by using an IDE when it really matters.
But it does make it more important to name your variables so they are clearly defining the purpose. But I am hoping you already are doing that. :)
This is more a simple personal attempt to understand what goes on inside Rascal. There must be better (if not already supported) solution.
Here's the code:
fileLoad = |home:///PHPAnalysis/systems/ApilTestScripts/simple1.php|;
fileAST=loadPHPFile(fileLoad,true,false);
//assign a simple id to each node
public map[value,int] assignID12(node N)
{
myID=();
visit(N)
{
case node M:
{
name=getName(M);
myID[name] =999;
}
}
return myID;
}
ids=assignID12(fileAST);
gives me
|stdin:///|(92,4,<1,92>,<1,96>): Expected str, but got value
loadPHPFile returns a node of type: list[Stmt], where each Stmt is one of the many types of statements that could occur in a program (PHP, in my case). Without going into why I'd do this, why doesn't the above code work? Especially frustrating because a very simple example is worked out in the online documentation. See: http://tutor.rascal-mpl.org/Recipes/Basic/Basic.html#/Recipes/Common/CountConstructors/CountConstructors.html
I started a new console, and it seems to work. Of course, I changed the return type from map[value,int] to map[str,int] as it was originally in the example.
The problem I was having was that I may have erroneously defined the function previously. While I quickly fixed an apparent problem, it kept giving me errors. I realized that in Rascal, when you've started a console and imported certain definitions, it (seems)is impossible to overwrite those definitions. The interpreter keeps making reference to the very first definition that you provided. This could just be the interpreter performing a type-check, and preventing unintentional and/or incompatible assignments further down the road. That makes sense for variables (in the typical program sense), but it doesn't seem like the best idea to enforce that on functions (or methods). I feel it becomes cumbersome, because a user typically has to undergo some iterations before he/she is satisfied with a function definition. Just my opinion though...
Most likely you already had the name ids in scope as having type map[str,int], which would be the direct source of the error. You can look in script https://github.com/cwi-swat/php-analysis/blob/master/src/lang/php/analysis/cfg/LabelState.rsc at the function labelScript to see how this is done in PHP AiR (so you don't need to write this code yourself). What this will give you is a script where all the expressions and statements have an assigned ID, as well as the label state, which just keeps track of some info used in this labeling operation (mainly the counter to generate a unique ID).
As for the earlier response, the best thing to do is to give your definitions in modules which you can import. If you do that, any changes to types, etc will be picked up (automatically if the module is already imported, since Rascal will reimport the module for you if it has changed, or when you next import the module). However, if you define something directly in the console, this won't happen. Think of the console as one large module that you keep adding to. Since we can have overloads of functions, if you define the function again you are really defining a new alternative to the function, but this may not work like you expect.
This is a very elementary question about the F# class syntax. Here is a little code to illustrate my problem.
type AClass() as self =
member this.Something = printfn "Hello"
Basically from what I have read the "as self" will create a name to the current instance which can be used in the entire class (like "this" in C# or Java). But "member this.Something" will do the same thing, only that the scope is limited to the method body. I guess I can see when you would use which syntax. The "as self" one can be used if you need it in the constructor or something and you can use the other one if you dont need it in the constructor.
But why do I have to use the "member this.Something" syntax even if I used the "as self" one? Why does it give me an error if I just write "member Something"? What have I missed?
Take care,
Kerr
The scope of as self is the whole class, while scope of this.Something is just an individual method. You don't often need as self since using this.Something is adequate.
Regarding why you need this. in member declaration, I think it's a natural choice since in F# classes you often have let bounds and static methods as well. Having self as default would cause confusion and misuse.
Here is an example using as self in MSDN, which is not common IMO:
type MyClass2(dataIn) as self =
let data = dataIn
do
self.PrintMessage()
member this.PrintMessage() =
printf "Creating MyClass2 with Data %d" data
It sounds like you've got all the differences between global 'as xxx' and member 'yyy.' instance binding sorted out. So I guess the answer to your answer has to be it's "by design".
Folks will argue that there is a deliberate rational behind this "by design" choice, but after 4 years of programming F#, my favorite language by far, I have personally not found it very helpful in any regard.
I suspect that the real reason the language requires explicit instance bindings to variables is because is more closely reflects the underlying .NET CIL implementation. That is, languages like C# bind "this" to the instance of a class definition as a feature. Under-the-hood, both static and instance methods of a class are called in the same manner using the Call and CallVirt opcodes, where in the case of instance methods the address of "this" is loaded as the first argument to the call.
But we've certainly ventured into the territory of taste and opinion.
I don't think this is duplication at all. self's visibility to the entire class is a by-product of F#'s "intelligent" compilation of primary constructors. The constructor's arguments/bindings can be implicitly compiled to both local and member (class-level) fields. The as identifier syntax merely facilitates this references within that mutant context. I'd venture to guess, if unused, it's compiled away. Otherwise, all you've done is stored an extra reference to this as a member field (which would seem bizarre in another language, such as C#).
There's this dichotomy in the way we can create classes in f# which really bothers me. I can create classes using either an implicit format or an explicit one. But some of the features that I want are only available for use with the implicit format and some are only available for use with the explicit format.
For example:
I can't use let inline* (or let alone) inside an explicitly defined class.
The only way (that I know) to define immutable public fields (not properties*) inside an implicitly defined class is the val bla : bla syntax.
But there's a redundancy here. Since I'll end up with two copy of the same immutable data, one private, one public (because in the implicit mode the constructor parameters persist throughout the class existence)
(Not so relevant) The need to use attributes for method overloading and for field's defaults is rather off putting.
Is there anyway I can work around this?
*For performance reasons
EDIT: Turns out I'm wrong about both points (Thanks Ganesh Sittampalam & MichaelGG).
While I can't use let inline in both implicit & explicit class definition, I can use member inline just fine, which I assume does the same thing.
Apparently with the latest F# there's no longer any redundancy since any parameters not used in the class body are local to the constructor.
Will be gone in the next F# release.
This might not help, but you can make members inline. "member inline private" works fine.
For let inline, you can work around by moving it outside the class and explicitly passing any values you need from inside the scope of the class when calling it. Since it'll be inlined, there'll be no performance penalty for doing this.