As I have played around with the TypeScript language, I got confused by the bahaviour of the class member shorthand syntax together with inheritance. Say you have the following valid TypeScript with two semantic intendical classes and an interface with one property:
class Person1 implements HasName {
constructor(public name: string) {}
}
class Person2 implements HasName {
public name : string;
constructor(name: string) {
this.name = name;
}
}
interface HasName {
name : string;
}
Now if you try to rename the 'name' property in the HasName interface, only the member in Person2 will be correctly renamed and in Person1 you will get an TypeScript error saying, that it doesnt implement HasName anymore.
With this behaviour in place, it won't be possible to safely use the shorthand syntax for class members :-/
Is this a bug or intended? As far as I'm concerned, a refactoring operation should never ever result in a compiler error. It should instead rename the short hand member in Person1 as well, which sounds like a bug to me.
If what you describe is true then I agree that it is a bug. But you have to distinguish between a language and a plugin to visual studio. Your bug is in the refactoring part of visual studio plugin not in the language itself. Note that there is a lot of bugs not implemented features as latest release (0.8.0) is an alpha.
Related
I want use generic interfaces that will be specified by their implementing classes, and all in all this has been working fine, like:
interface Remove <E> { fun remove(entity: E) }
class MyHandler : Remove <MyClass> {
override fun remove(entity: MyClass) { */do stuff/* }
}
However, I have a case (so far, expecting more to come) where I want the function itself to be generic. Writing the interface is no problem at all:
interface FindByID <E> { fun <K : Serializable> findByID(id: K): E }
I need K to be serializable because that's a requirement of some function I need to call.
The compiler doesn't seem to agree with my implementation attempt. When I do this:
override fun <String> findByID(id: String): User {
return someFunction(User::class.java, id) as User
}
I get two compiler errors:
overrides nothing
id is not Serializable
However, when I remove override and <String> from the signature, it works fine. This means String is serializable, which my research shows as well.
What seems to be the problem here?
Also, yes, I know that I could work around this issue in a couple of ways, like
making the interface function accept Serializable instead of <K : Serializable>
not specifying K on override, but on call (myHandler.findByID<String>("myID"))
"rerouting" the call, implementing (not overriding) in MyHandler a function that accepts Strings and then internally calls the overriden function
Although open to suggestions, I'm less interested in workarounds, but would rather like to understand and (if possible) solve the actual problem or at least know it can't be done so I can take that into account for planning
The current problem
With your current declaration of <String>, you're not specializing the type parameter as you might think. What you're actually doing is declaring a type parameter that happens to be named String (nothing to do with the well-known String type, just an unfortunate name collision). With syntax coloring, you should see that String here is in the color of a type parameter, not the same color as the String type would be. Change this name to anything else, and you'll realize the confusion.
So if we rename this to K, the problems become obvious: problem 1 "overrides nothing" is because your generic type parameter doesn't have the same : Serializable constraint as the findByID method defined in the interface. And problem 2 stems from it.
Solutions
Also, yes, I know that I could work around this issue in a couple of ways, like
not specifying K on override, but on call (myHandler.findByID("myID"))
This point is actually the essence of the issue, not a workaround: defining a generic function in your interface actually makes it part of the contract for this function to be generic.
Implementations must have a generic type parameter here.
What to do to fix it depends on what you expect to happen.
If you're ok with having generic functions in your implementations, then leave the interface as you declared it, but accept that the implementations have to deal with all possible values of K, which is most likely not what you want here.
If you want to define a specific type in your implementations, K should be part of the interface definition (not the interface method), and the method should not have a type parameter itself, but simply accept the existing K from the interface:
interface FindByID<E, K : Serializable> {
fun findByID(id: K): E
}
I updated an application JDK from 1.6 to 1.8 but I kept the language level 1.6 in IntelliJ.
After updating I got compilation error in some tests in assertThat statements with checking type of an object. The code is like this:
assertThat((Class) myList.get(0).getMyClassType(), is(equalTo(MySubclass.class)));
myList is looking like this:
List<MyClassDefinition> myList = myClassDefinition.getMyClassDefinitions(reader);
Where definition of MyClassDefinition and getMyClassType() are like this:
public class MyClassDefinition {
private Class<? extends MyClass> classType;
public Class<? extends MyClass> getMyClassType() {
return classType;
}
}
and MySubclass is Myclass's subclass:
public class MySubclass extends MyClass {
#Override
public void initialise() {
// some action here!
}
}
The definition of MyClass is
public abstract class MyClass extends AnotherClass<AnotherType>{
//Definitions
}
The import for Assert is and equals library is this:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
and the hamcrest version is hamcrest-all-1-3
After changing project SDK to jdk 1.8 I am getting this error message:
Error:(136, 9) java: no suitable method found for assertThat(java.lang.Class,org.hamcrest.Matcher<java.lang.Class<MySubClass>>)
method org.hamcrest.MatcherAssert.assertThat(java.lang.String,boolean) is not applicable
(argument mismatch; java.lang.Class cannot be converted to java.lang.String)
method org.hamcrest.MatcherAssert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
method org.hamcrest.MatcherAssert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>))
application is build with Ant and we have added hamcrest jar file to class file, so there is no change when we are altering JDK in project.
So my question is why this code is working with JDK 1.6 but not working with 1.8 while I am using same level of language (1.6) for compilation? Is it depend to different libraries some how?
Apparently, you had a problem with the generic type signatures which you worked around by inserting a type cast to the raw type Class, which causes the compiler to treat the entire statement as an unchecked operation using raw types only.
As you can see from the compiler message, org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>, it now did a generic type check which (correctly) failed, but imho, it shouldn’t do that type check under Java 6 language rules. The problem stems from the fact that JDK8 doesn’t include the original Java 6 compiler but rather let the new compiler attempt to compile using the old rules, which may not be that precise.
But regardless of whether the behavior is correct or not, I wouldn’t expect a fix for it, as emulating the old Java 6 language rules is not of a high priority.
Note that with source level 1.8, the code compiles without problems, even without the raw type cast. The original problem stems from the restrictive signature of CoreMatchers.equalTo(…). The standalone expression equalTo(InstanceOfFoo) returns a Matcher<Foo>, which being passed to assertThat allows to only test instances of Foo (it’s even worse when using isA(Foo.class) which also can only test instances of Foo, which makes the test pointless).
With Java 8, there is target type inference, which allows, e.g.
Matcher<Object> m = equalTo(InstanceOfFoo);, which will infer Object for <T> and passes, as InstanceOfFoo is also assignable to Object. This also works in conjunction with the compound assertThat statement of your question, inferring a suitable type.
This guides us to the general solution that works with all language levels. Just use
assertThat(myList.get(0).getMyClassType(), is(equalTo((Object)MySubclass.class)));
Class<MySubclass> is, of course, assignable to Object which makes the cast a no-op. But then, getting a Matcher<Object>, you can check every object you like, including the result of myList.get(0).getMyClassType(), which is, of course, also assignable to Object. Unlike your original workaround, this doesn’t bear any raw type usage nor unchecked operation.
You could also use an explicit type instead of a cast, CoreMatchers.<Object>equalTo(MySubclass.class), but this eliminates the benefit of import static.
By the way, when matching Class objects, you may use sameInstance instead of equalTo.
I have a portable class library that I am using MvvmCross in. I thought it would be good to centralise various MvxValueConverter classes into this library as they will be used extended or used by different platforms/dlls.
For instance I created the class:-
namespace MyCompany.Core.ValueConverters
{
public class InverseBoolValueConverter : MvxValueConverter<bool, bool>
{
protected override bool Convert(bool value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !value;
}
}
}
The problem I am seeing however is that the output is throwing the following warning:-
warning CS3009: 'MyCompany.Core.ValueConverters.BoolValueConverter': base type 'Cirrious.CrossCore.Converters.MvxValueConverter' is not CLS-compliant.
I guess I am not sure if this is an issue or something that I can ignore and secondly - why is it not CLS complaint?
Any help would be appreciated.
Kind regards
Alan.
My guess is simply that you have [assembly:CLSCompliant(true)] in your assembly while MvvmCross doesn't have that set - see Base type is not CLS-compliant, what reasons of this warning?
If your project does care about interop with other languages and about strict CLS compliance, then there is a lot of info on it at http://msdn.microsoft.com/en-us/library/12a7a7h3(v=vs.110).aspx#Generics and you can find more about it here by including the C# and cls-compliant tag - e.g. https://stackoverflow.com/questions/tagged/cls-compliant
public class A extends B implements C {
}
Class B and interface C have the same member function name(not the same signature).
This code can't be compiled. How can I solve this?
The inherited class implements your interface method, so there should not be an error. In fact, both having the same name is really the idea of implementing an interface...
Here's a check list:
The method must have not only the same name, but the same signature. Make sure you've specified the correct argument and return types (this includes initial values).
If your sub class A also implements the same method, you must mark it as override. Same rules apply regarding the signature.
If you do override B's method, it must not be declared final.
If your class does not have the exact same method name AND signature, it is not properly implementing your interface. That's the long and short of it. You can either remove the implementation or change the method signature to fix it.
I am trying to create an ActionScript 3 class that implements two interfaces. The interfaces contain member functions with different signatures but the same name:
public interface IFoo
{
function doStuff(input:int):void;
}
public interface IBar
{
function doStuff(input1:String, input2:Number):void;
}
public class FooBar implements IFoo, IBar
{
// ???
}
In C# (for example) this is not a problem because methods can be overloaded, but ActionScript does not support overloading. Is there any way to create a class that implements both interfaces?
No, unfortunately this is not possible and it's because of the reason you already pointed out: ActionScript 3 does not support member overloading. It's a shame, but it's the unfortunate truth.
It is possible to have multiple members with the same name and even the same signature in a class, however, they must be qualified by namespace in that case. For instance, this should work:
public namespace foo;
public namespace bar;
foo function doStuf(input:int):void
{
// ...
}
bar function doStuff(input1:String, input2:String):void
{
// ...
}
You then reference the methods by qualifying them like so:
foo::doStuff(1);
bar::doStuff("foo", "bar");
Unfortunately, this won't help with your problem because even though the namespaces may be in the public namespace, they are still not the same as the public namespace itself meaning you're not satisfying the contract set forth by the interfaces (everything must be public). Making a long story short; unless you use some sort of composite pattern, you're out of luck until Adobe decides to implement member overloading.
public class FooBar would have to implement both interaces and thus implment those functions listed. Problem is ActionScript does not support method overloading. It is a nice feature that I miss from C# :(