What is type of native constructor which throws exception in Frege? - frege

I'm trying to figure out native interface. I'm trying to send some message using UDP. Here what I have:
module UDPTest where
data StringAsBytes = native java.lang.String where
native getBytes :: String -> ST s (Mutable s (JArray Byte))
data InetSocketAddress = native java.net.InetSocketAddress where
native new :: String -> Int -> ST s (Mutable s InetSocketAddress)
data DatagramPacket = native java.net.DatagramPacket where
native new :: Mutable s (JArray Byte) -> Int -> Mutable s InetSocketAddress -> ST s (Mutable s DatagramPacket)
data DatagramSocket = native java.net.DatagramSocket where
native new :: () -> IOMutable DatagramSocket throws SocketException
native send :: Mutable RealWorld DatagramSocket -> MutableIO DatagramPacket -> IO () throws IOException
native close :: MutableIO DatagramSocket -> IO ()
data SocketException = native java.net.SocketException
derive Exceptional SocketException
main _ = do
messageStr = "hello world;\n"
messageAsBytes <- StringAsBytes.getBytes messageStr
address <- InetSocketAddress.new "localhost" 3003
messageLen <- messageAsBytes.getLength
packet <- DatagramPacket.new messageAsBytes messageLen address
socket <- DatagramSocket.new ()
socket.send packet
socket.close
This code accidentally runs but it makes me wonder few things. Firstly, what should be a type of DatagramSocket.new to reflect the fact of throwing exception? I had tried to pack it into Maybe but it ended up in a total mess. Is there any way to do it? For now, I have no idea how to handle exceptions in main and this doesn't address it fully or maybe I'm missing something.
Secondly, Why I was forced by compiler to change InetSocketAddress from pure to impure, to use it in DatagramSocket.new? I was also forced to use mutable version of JArray wherever it was needed in code.

Concerning exceptions: There are 2 ways of managing exceptions.
The first is by wrapping the return type in an Either. This will give you the value you want in Right and the exception in Left when it occures.
To handle the exception, you generally use pattern matching or the either function. Unfortunately, in IO code (like in your case) this would lead to code like
do
r1 <- Socket.new ...
case r1 of
Left -> -- handle exception
Right x -> do
r2 -> x.send ....
case r2 of
....
which is not so nice. Therefore, the Either style is preferred for pure functions, and for IO/ST actions the other style is preferred.
For this, declare your native functions with a throws ... clause, as you have done already for send and new. The exception aware IO/ST action then looks like:
foo = do
s <- Socket.new
d <- s.send ....
...
`catch` (\x1::SocketException -> ...)
`catch` (\x2::IOException -> ....)
....
`finally` finallyaction
There may be as many catches as you need, but make sure to order them so that the most specific one comes before the less specific one, i.e. if ExceptionDerive extends ExceptionSuper, then the catch for ExceptionDerived must occur before the other one.
The finally clause is optional. Note that you don't have access to variables bound in the do block neither in the catch clauses nor in the finally clause. If you need this, you need to do the exception handling on a lower level (i.e., where some variable is bound to the value you need).
Please look up catch and finally in the frege doc or on Froogle.
Make sure the catch is indented less than the code in the do it guards. This is to make sure the compiler sees:
do { .... } `catch` handler
You can as well write code without caring about exceptions, and add them only later. For example, you start with:
action1 a b c = do
dothis a
dothat b
dosomethingelse c
pure whatyouwant
Later, you can rename action1 to action1noex and write
action1 a b c = action1noex a b c
`catch` ....
Second point. For data types that can only be used in the IO Monad, it is recommended to declare them as
data Socket = mutable native java......
This makes it possible to simply write Socket instead of Mutable s Socket or Mutable RealWorld Socket, since the compiler knows that such a value will always be mutable. You can use such types only in native functions that have a IO result.
Conversely, for data types that you just construct but never use in an impure way, you can define them as pure native.
I'm not sure about InetSockAddress but I guess it is not modified once constructed?
Likewise, rgd. the byte array. If you always and only ever want to convert this from and to strings, it can be treated as an utf8 text type (which we unfortunately don't have yet in the library). This would look like
data Charset = pure native java.nio.charset.Charset
pure native utf8 "java.nio.charset.StandardCharsets.UTF_8" :: Charset
data Bytes = pure native "byte[]"
pure native getBytes :: String -> Charset -> Bytes
pure native getString new :: Bytes -> Charset -> String
toBytes s = getBytes s utf8
fromBytes bs = getString bs utf8
(untested, please ignore the warning concerning byte[] for now)

Firstly: you can wrap result of function (method) throwing exception into Either, like this: native fn :: A -> Either SomeException B or sugared version: native fn :: (SomeException | B).
Secondly: Frege values are immutable. If you have got some data type A defined in Frege it is immutable. You are allowed to wrap some Java types and for immutable you mark them pure: data D = pure native com.acme.D. InetSocketAddress is not declared pure. This means that ImmutableSocketAddress can be changed by some other thread anywhere in time(for example closing socket). So Frege compiler marks it as Mutable. You can pass such data to Java functions only wrapped with Mutable taint.
You can write a function in Frege that doesn't need Mutable taint, but to pass it an argument you need to use some readonly or Freezable to get rid of Mutable.

Related

How to avoid the error "staticCFunction must take an unbound..." in Kotlin Native when a Kotlin callback function is called from C?

This is a general question about callback functions, defined in Kotlin Native, called by C functions.
For argument's sake, let's say I'm trying to walk a directory in a filesystem recursively, using https://linux.die.net/man/3/nftw in Kotlin Native.
(I know there are other ways to do this, using other C functions, but that is not the core of this question.)
nftw() takes a function as a callback:
val directory = "//some/directory"
val callback = kotlinx.cinterop.staticCFunction {
file: CPointer<ByteVar>?,
stat: CPointer<stat>?,
typeFlag: Int,
b: CPointer<FTW>? ->
val fileName = file?.toKString()
println(fileName)
val result = 0
result
}
val depth = 10
val flags = 0
platform.posix.nftw(directory, callback, depth, flags)
This works for listing files via "println()", but as as soon as the lambda contains any captured value, I get the following compiler error:
"kotlinx.cinterop.staticCFunction must take an unbound, non-capturing function or lambda".
My question is: is there any recommended approach on how to
access any non-global state from such a callback?
I did come up with a nasty workaround using a global variable, so that's not what I'm looking for primarily. If there is a commonly accepted solution using #ThreadLocal or something else, please discuss.
For native callbacks in general (not specific to nftw). The C function should accept a void* userData parameter and pass it to the callback when it is called. This allows you to pass local data to the callback, instead of global data.
This is the case even in C/C++.
For this particular case (regardless of language) there isn't really a way to do this without some global data (or JIT but let's not think about it). So any workaround would have to be nasty.
Using #ThreadLocal is a "reasonable nasty" solution.
nftw is just not a well designed C interface.

Type is not as polymorphic as suggested

I'd like to build an abstraction to use different template engines:
class Template a where
process :: a -> Model -> IO String
class TemplateEngine a where
buildTemplate :: (Template b) => a -> BufferedReader -> IO b
My first attempt is to adapt Groovy templates so I implemented the needed data types:
data GroovyWritable = mutable native groovy.lang.Writable where
native writeTo :: GroovyWritable -> Writer -> IO Writer
throws IOException
data GroovyTemplate = mutable native groovy.text.Template where
native make :: GroovyTemplate -> HashMap -> IO GroovyWritable
data GroovyEngine = mutable native groovy.text.markup.MarkupTemplateEngine where
native new :: () -> IO GroovyEngine
native createTemplate :: GroovyEngine -> BufferedReader -> IO GroovyTemplate
throws ClassNotFoundException, IOException
Then I did the correspondent instances:
instance Template GroovyTemplate where
process template model = do -- model is not used at the moment
config <- HashMap.new ()
writable <- GroovyTemplate.make template config
stWriter <- StringWriter.new ()
writer <- writable.writeTo stWriter
writer.toString
instance TemplateEngine GroovyEngine where
buildTemplate engine reader = GroovyEngine.createTemplate engine reader
But the compiler is complaining with:
...
type `GroovyTemplate` is not as polymorphic as suggested
in the annotation where just `α` is announced.
...
type error in expression createTemplate engine reader
type is : IO GroovyTemplate
expected: IO α
Any ideas ? Should I be using a different strategy ?
Thanks
UPDATE:
In order to explain what I'm trying to do I'm adding a function representing a generic way of building a template from a given template engine.
Lets say I haveI understand that Frege needs to be more precise about the types, an instance of TemplateEngine and a BufferedReader containing the content of a template file, executing the buildTemplate function of a given engine should give me in return an instance of Template. This function here is compiling with no warnings at all.
execute :: (TemplateEngine a, Template b) => a -> BufferedReader -> IO b
execute engine reader = buildTemplate engine reader
I'm confused, why compiler is not complaining here ? Shouldn't it be complaining same way it did before ?
UPDATE II (Working Solution):
Following Ingo's recommendation I went through the rationale behind my design and I've found a working solution.
In the beginning I thought it would be great to haveTemplateEngine type class to create template engine instances the same way.
But the most important part was to have a common type class for dealing with templates, among other things, because templates can be cached. So the bottom line is that I don't care how templates are coming from as long as the resulting template is an instance of Template.
Following that premise then I can have a common function to process a template and get the resulting html/json/xml...etc.
execute :: (Template a) => a -> Model -> IO String
execute tpl model = tpl.process model
Of course the production-ready signature should be something like:
execute :: (Template a) => a -> Model -> Either TemplateException String
I'm not entirely sure what you are about to do, but as it stands, the GroovyEngine.createTemplate method cannot be used to instantiate teh GroovyEngine as TemplateEngine. Since the buildTemplate operation promises to return any Template the caller wants, provided that a Template instance is passed as argument.
Now, the first problem here is that native methods can't deal with type class constraints. We could work around this problem by wrapping the call to the native method with a frege function that actually uses the Template constraint. But then again, it is not clear how to actually create an appropriate value, since the Template class doesn't offer a corresponding operation. And the GroovyEngine.createTemplate still doen't qualify, because it always creates a specific template, not one that depends on the constraint.

How do I declare Maybe of a mutable type in an non-pure native function in Frege?

The native-gen tool generates the native declaration for the
showOpenDialog method in javafx.stage.FileChooser like so
data FileChooser = mutable native javafx.stage.FileChooser where
native showOpenDialog :: FileChooser -> Window -> IO File
Compiling leads to the message
Non pure native type File must be MutableIO
File in IO actions.
Now setting
native showOpenDialog :: FileChooser -> Window -> MutableIO File
leads to
FileChooser.showOpenDialog has an illegal
return type for a method that is not pure, perhaps ST s (MutableIO
File) would work
but following the advice leads to first error message again.
The compiler accepts IOMutable File as return type, which makes sense
since it is an IO action that returns a mutable type.
If possible, the compiler error message should be adapted to avoid frustration on the user side.
However, in this special situation, the file can be null and so
the core type is not File but Maybe File.
But then just using IOMutable (Maybe File) leads to the rather surprising message
The type MutableIO (Maybe File) is illegal,
Maybe File must be a native type.
Any advice on how to properly declare this type?
The code generated by native-gen is wrong because File has been declared as IO in native-gen but File is actually defined as a stateful (not IO) native type as can be seen from here.
IOMutable is defined as type IOMutable d = IO (MutableIO d).
For your case, the mutable native type (MutableIO d) can be null so the following should work:
data FileChooser = mutable native javafx.stage.FileChooser where
native showOpenDialog :: FileChooser -> Window -> IO (Maybe (MutableIO File))

Warning on native mutable field

What does this warning mean? Is there any way we can avoid this warning? I tried to understand the message from the compiler code here but I couldn't.
frege> native sysin "java.lang.System.in" :: InputStream
native function sysin :: InputStream
3: note that the java expression
java.lang.System.in is supposed to be
constant.
I also tried the code below but got the same warning:
frege> native sysin "java.lang.System.in" :: MutableIO InputStream
native function sysin :: MutableIO InputStream
3: note that the java expression
java.lang.System.in is supposed to be
constant.
It is simply a reminder that the java value could change over the lifetime of the program, but you, the programmer, assume its de-facto immutability by using this notation.
In fact, one can re-assign those fields on the Java level. In this case, Frege code could still return the previous value that it may have cached somewhere. Or it could violate referential transparency, so that sysin does not mean the same everywhere.
If you need to make sure that you get the current value of a mutable field, you need to declare it as IO or ST.
This feature is thought as a relief for the cases when we know that a value won't change, so that we can write:
dosomething sysin
instead of
sysin >>= dosomething
This is used, for example, in frege.java.IO, where stdin, stdout and stderr are defined that way.
The warning cannot be supressed, except by compiling with nowarn. This feature should simply not be used unless you're absolutly sure you're doing the right thing, that is, when a proper IO or ST action would produce the very same value all the time.

Java 8 cyclic inference warning

My knowledge about list operations is from scripting languages. So in Java I stopped on something strange in case of finding cookie with particular name.
List<Cookie> cookies = Arrays.asList(request.getCookies());
String auth = cookies.stream()
.filter(c -> c.getName().equals("auth"))
.map(Cookie::getValue);
On the map method IntelliJ is showing me "Cyclic inference".
Java compiler Error:(52, 25) java: incompatible types: no instance(s) of type variable(s) R exist so that java.util.stream.Stream conforms to java.lang.String
Your current code returns a Stream<String>, so you need an extra step to return a string:
Optional<String> auth = cookies.stream()
.filter(c -> c.getName().equals("auth"))
.map(Cookie::getValue)
.findAny();
Note that it returns an Optional<String> because there may be no Cookie that matches "auth". If you want to use a default if "auth" is not found you can use:
String auth = cookies.stream()
.filter(c -> c.getName().equals("auth"))
.map(Cookie::getValue)
.findAny().orElse("");
In essence, what this rather cryptic error message is saying is "the output of the stream sequence doesn't match what you are assigning it to in the end", ex:
String s = list.stream().map(s -> s); // this doesn't result in a String...
.findFirst().get()
So to debug compilation, remove the assignment (temporarily), or, as the other answer says, add something that makes it return a String by collecting (ex: .collect(Collectors.joining(","))) or (getting like .findFirst().get()), or change the assignment, like Stream<String> stream = list.stream().map(...)