Java type inference fails: <captured wildcard> is not a functional interface - javac

With the java 8 compiler, this program:
import java.util.function.Consumer;
public class xx {
public void execute(Consumer<? super Runnable> executor, Runnable action) {
executor.accept(() -> action.run());
}
}
fails with:
xx.java:4: error: incompatible types: <captured wildcard> is not a functional interface
executor.accept(() -> action.run());
^
Obviously the compiler failed to infer the type of () -> action.run().
This is easy to fix either by changing ? super Runnable to Runnable, or by explicitly casting the lambda to Runnable.
My question: this failure seems kindof "dumb".. is this behavior specified by the JLS, or is this a compiler bug?

Capture of ? super Runnable represents a given but unknown super type of Runnable (could possibly be Object). To classify a type as a functional interface you need an upper bound, not a lower bound. Inferring the type of a lambda, OTOH, requires a function interface as its target type.

Related

[F#][sharppcap][Error] "A type instantiation involves a byref type." what is a workaround in F#

I try to use SharpPcap in F#, but I was blocked by this compiler error for two days.
I find the most releate answer is What is the error "A type instantiation involves a byref type." and what is a workaround in F#, but do not fit my context well.
Please help me work around it, Thank you!
open System
open SharpPcap
open SharpPcap.LibPcap
let device = new CaptureFileReaderDevice("test.pcap")
// try workaround 1
let new_package (sender: Object) (e: PacketCapture) = ()
let handler = new PacketArrivalEventHandler(new_package)
device.OnPacketArrival.AddHandler(handler)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
// try workaround 2
let new_package (e: PacketCapture) = ()
device.OnPacketArrival.Add(new_package)
// error: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
I think the error is because:
public event PacketArrivalEventHandler OnPacketArrival;
public delegate void PacketArrivalEventHandler(object sender, PacketCapture e);
public readonly ref struct PacketCapture
{...}
The delegate PacketArrivalEventHandler use PacketCapture as param type, but this is a readonly ref struct which can not use to define F# function to add to Event OnPacketArrival.
Pls help me workaround it, Thank you!
I want make this line pass the F# compiler:
device.OnPacketArrival.Add(new_package)
In c# it used in this way:
device.OnPacketArrival += new_package
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
You can't do this by using the F# IEvent first-class listening points, because in this case the type of device.OnPacketArrival ends up being IEvent<PacketArrivalEventHandler, ref<PacketCapture>>, whose second type parameter ref<PacketCapture> is not allowed. This is what the error message tells you.
But you can use the underlying .NET add_ and remove_ methods, which are analogs of property get_ and set_ methods, but for events. F# allows you to call these "hidden" methods explicitly, even though they're not listed in IDE completion lists.
device.add_OnPacketArrival handler
It works, because it's directly calling a method on the device object, rather than creating a wrapping value of type IEvent<...> and then calling .Add or .AddHandler on it.

Is there a neater way to map member functions in dart?

Dart has a handy map function on iterables, and it accepts a lambda. So I can write something like:
// Stupid example class
class Foo {
int v;
int v2() { return v*v; }
}
List<int> mapFoos(List<Foo> foos) {
return foos.map( (Foo f) => f.v2() );
}
But this feels a little clunky to me. I'm used to being able to tell map to use the member function directly, something that would look more like:
// does not compile
List<int> mapFoos(List<Foo> foos) {
return foos.map(Foo.v2);
}
But this fails to compile with the error:
The argument type '() → int' can't be assigned to the parameter type '(Foo) → int'
Is there some way to turn the member function into a lambda in a succinct way, so that
we can have something closer to the second example.
I could write
int applyV2(Foo f) {
return f.v2();
}
List<int> mapFoos(List<Foo> foos) {
return foos.map(applyV2);
}
but then I'd need to create that for each member function I want to map, which isn't really any better than using the lambda function.
If it makes any difference I'm using dart 1 due to "legacy reasons", if this has changed in recent versions I'd love to know that too.
No.
There is no shorter way to create a function which takes a Foo and calls its v2 method, than (f) => f.v2().
You can omit the Foo type on the parameter, because it can be inferred from the context (a List<X>.map<R> requires an R Function(X) as argument).
You cannot tear off Foo.v2 because v2 is an interface method, not a static method.
Just to elaborate on why Dart doesn't allow that, you can stop reading now if you just want to know what works:
Some languages allow you to tear off instance methods, so Foo.v2 becomes a function which expects its this object as an argument, in Dart a function of type int Function(Foo). Dart does not allow that. Probably for many different reasons, but most importantly because it cannot work. Dart types are interfaces, all class types can be implemented by another class without inheriting any implementation.
If you then tear off Foo.v2, you can call it with an instance of another class which implements Foo, but which won't necessarily find the private fields that Foo has, and which v2 could depend on.
Also, the tear-off would be covariant in its this-parameter.
Take SubFoo which extends Foo and has its own v2 method. If you do Foo foo = SubFoo(); var vtoo = foo.v2; then the static type of vtoo will be int Function(Foo), but the implementation from SubFoo will necessarily have runtime type int Function(SubFoo), which is not a subtype of the static type. That means it's unsound. The torn off function will have to do a run-time type check that its argument is actually a SubFoo, and throw if it's not. (So, that feature is not a good match for Dart.)

dart lambda type inference

void main() {
print(doStuff.runtimeType);
print(((e) => doStuff(e)).runtimeType);
}
int doStuff(String hallo) {
return 42;
}
executed in the dartpad yields
(String) => int
(dynamic) => int
I would expect both to have the same type. Can somebody explain why dart fails to infer the type of the argument e?
Dart type inference is limited in some ways that inference in purely functional languages is not.
It's not constraint solving based.
So, when the compiler sees (e) => doStuff(e), it checks whether there is a context type from which it can deduce the parameter type.
There isn't (being the receiver of .runtimeType provides no hint). So, it infers dynamic for the parameter, which needs a type before the body of the function can be type analyzed at all.
Then it looks at the body and sees that doStuff(e) is valid and has type int, so that becomes the return type.

Nullability mismatch in simple assignment after switching to sound null safety

I switched to sound null safety and started getting runtime error in a simple assignment, that should never happen with sound null safety:
final widgetOnPressed = widget.onPressed;
Error:
type '(LogData) => void' is not a subtype of type '((LogData?) => void)?'
I can repro it for Flutter versions 2.12.0-4.1.pre and 2.13.0-0.0.pre.505.
PR: https://github.com/flutter/devtools/pull/3971
Failing line: https://github.com/flutter/devtools/blob/9fc560ff2e6749459e2ca6a1dc00bf6fb16ed93b/packages/devtools_app/lib/src/shared/table.dart#L1184
To repro, start DevTools at this PR for macos, connect to an app and click the tab 'Logging'. DevTools will show red screen and error in console.
Is it dart bug or the app bug? If it is the app bug, how can I debug it?
It's a bug in your code.
You didn't say which kind of error you got - a compile-time error or a runtime error. I'm guessing runtime error. (Well, you did say to launch it in the debugger, so that is a good hint too.)
The line final widgetOnPressed = widget.onPressed; looks like it can't possibly fail. After all, the type of the local variable is inferred from the expression assigned to it, and the runtime value of that expression will surely be a subtype of the static type because the type system is sound!
Isn't it? ISN'T IT?
It's not, sorry. Dart 2's type system is mostly sound, even more so with null safety, but class generics is covariant, which can still be unsound. It's fairly hard to hit one of the cases where that unsoundness shows its ugly head, but returning a function where the argument type is the class's type variable is one.
Your state class extends State<TableRow<T?>>, so the widget getter returns a TableRow<T?>. The onPressed of that type has type ItemCallback<T?>?, aka, void Function(T?)?.
You create a _TableRowState<LogData>, with its widget which has static type TableRow<LogData?>, but you somehow manage to pass it a TableRow<LogData> instead. That's fine. Class generics are covariant, so all is apparently fine at compile-time.
Then you do final widgetOnPressed = widget.onPressed;.
The static type of widgetOnPressed is void Function(LogData?) here.
The actual runtime type of onPressed is void Function(LogData) because it's from a TableRow<LogData>.
A void Function(LogData) is-not-a void Function(LogData?) because the former cannot be used in all places where the latter can (in particular, it can't be used in a place where it's called with null).
This assignment is potentially unsound, and actually unsound in this case. The compiler knows this and inserts an extra check to ensure that you don't assign a value to the variable which isn't actually valid. That check triggers and throws the error you see.
How do you avoid that?
Don't create a TableRow<LogData> where a TableRow<LogData?> is required.
Or type the variable as:
final ItemCallback<T>? widgetOnPressed = widget.onPressed;
(no ? on the T).
Or rewrite everything to avoid returning a function with a covariant type parameter (from the class) occurring contra-variantly (as an argument type).
Which solution fits you depends on what you want to be able to do.

HackLang by Facebook is not strict

Good day,
I have problem. I want to simulate some errors in hacklang.
<?hh
namespace Exsys\HHVM;
class HHVMFacade{
private $vector = Vector {1,2,3};
public function echoProduct() : Vector<string>{
return $this->vector;
}
public function test(Vector<string> $vector) : void{
var_dump($vector);
}
}
Function echoProduct() returns Vector of strings. But private property $vector is Vector of integers. When I call echoFunction and returning value use as argument for function test(). I get
object(HH\Vector)#35357 (3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
Why? I am expecting some error because types mismatch.
There's two things at play here:
Generics aren't reified, so the runtime has no information about them. This means the runtime is only checking that you're returning a Vector.
$this->vector itself isn't typed. This means the type checker (hh_client) treats it as a unknown type. Unknown types match against everything, so there's no problem returning an unknown type where a Vector<string> is expected.
This is to allow you to gradually type your code. Whenever a type isn't known, the type checker just assumes that the developer knows what's happening.
The first thing I'd do is change the file from partial mode to strict mode, which simply involves changing from <?hh to <?hh // strict. This causes the type checker to complain about any missing type information (as well as a couple of other things, like no superglobals and you can't call non-Hack code).
This produces the error:
test.hh:6:13,19: Please add a type hint (Naming[2001])
If you then type $vector as Vector<int> (private Vector<int> $vector), hh_client then produces:
test.hh:9:16,28: Invalid return type (Typing[4110])
test.hh:8:44,49: This is a string
test.hh:6:20,22: It is incompatible with an int
test.hh:8:44,49: Considering that this type argument is invariant with respect to Vector
Which is the error you expected. You can also get this error simply by adding the type to $vector, without switching to strict mode, though I prefer to write my Hack in the strongest mode that the code supports.
With more recent versions of HHVM, the type checker is called whenever Hack code is run (there's an INI flag to turn this off), so causing the type mismatch will also cause execution of the code to fail.

Resources