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 inRight
and the exception inLeft
when it occures. To handle the exception, you generally use pattern matching or theeither
function. Unfortunately, in IO code (like in your case) this would lead to code likewhich 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 forsend
andnew
. The exception aware IO/ST action then looks like:There may be as many
catch
es 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. Thefinally
clause is optional. Note that you don't have access to variables bound in thedo
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:You can as well write code without caring about exceptions, and add them only later. For example, you start with:
Later, you can rename
action1
toaction1noex
and writeSecond point. For data types that can only be used in the IO Monad, it is recommended to declare them as
This makes it possible to simply write
Socket
instead ofMutable s Socket
orMutable 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
(untested, please ignore the warning concerning
byte[]
for now)