The Control.Exception documentation says I can do the following to create my own exception:
data MyException = ThisException | ThatException
deriving (Show, Typeable)
instance Exception MyException
If I paste this into a file and compile (after importing Control.Exception and Data.Typeable), I get:
exp.hs:6:20:
Can't make a derived instance of `Typeable MyException'
(You need -XDeriveDataTypeable to derive an instance for this class)
In the data type declaration for `MyException'
Must I turn on this extension in order to have user-defined exceptions? If not, someone please provide an example. Thanks.
Yes, you need to turn on that extension. It's not a good idea to try to write the Typeable instance by hand because it has some ties to the internals of GHC.
Related
I've been trying to figure out how exceptions work in Racket, but I'm a bit puzzled on the exception predicates. To catch an exception of say exn:fail type, you test it with a predicate exn:fail? in a with-handlers expression. I've found the documentation on exn:fail, but I don't see where exn:fail? is documented. Why I'm so curious about this is according to this article, if you make a custom exception struct of say exn:no-vowels, you can still use exn:no-vowels? despite the fact that this predicate was never manually implemented. If I had to wager a guess, the predicate must have been generated automatically with a macro, but if so I'm curious to know where this "automatically generate predicates behavior" is documented and how the macro works exactly.
exn and derived exception types like the exn:fail hierarchy are all instances of Racket structure types, and predicates, constructors and accessors (like exn-message) are automatically defined when they're created with the struct macro.
User defined exception types can be exported from a module with struct-out in a provide form, which exports all those generated functions without you having to list them manually.
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 understand that the "msg" field can be accessed by
(.getMessage (ex-info "message" {:a 123}))
However, I just don't see the reason that ExceptionInfo has a msg field. Clojure core doesn't even provide an proper interface to access this field, e.g. (ex-msg (ex-info ...)).
Does anyone have an example to show how to use this msg field?
In Java, the base Throwable class from which all exceptions extend has a detailMessage field and the ExceptionInfo class inherits it. The JVM will display this message when an exception is thrown.
So, the ex-info has a message to satisfy the class hierarchy above it and to work in standard ways with Java and the JVM. The typical way to use it is to use standard Java interop call to .getMessage like you've done in the question. You will also see it you use things like pst.
I want to switch between xmobar configurations on the fly by using key combinations. I have naively tagged the following onto my other key mods:
, ((controlMask, xK_l), xmproc <- spawnPipe "/usr/bin/xmobar /home/tony/.xmobarLrc")
, ((controlMask, xK_w), xmproc <- spawnPipe "/usr/bin/xmobar /home/tony/.xmobarWrc")
and the compiler barfs at <-. You can probably read my intention in the code. I am no Haskell expert and I'm slowly building up the environment I want by using a lego approach, but that has failed me here.
Where am I going wrong?
TIA
Well, it's quite complicated to do what you want. You can use the extensible state module from the xmonad-contrib library.
For that, you have to add a LANGUAGE pragma at the top of your xmonad configuration file:
{-# LANGUAGE DeriveDataTypeable #-}
You need it to derive the Typeable instance for the data type that stores the xmobar handle.
newtype XMobarHandle = XMobarHandle { xmhandle :: Maybe Handle } deriving Typeable
instance ExtensionClass XMobarHandle where
initialValue = XMobarHandle Nothing
Now you can define the key-binding, which retrieves the current xmobar handle from the extensible state, closes it if it is not Nothing, spawns a new one and puts it into the state.
((controlMask, xK_l), do
mh <- xmhandle `fmap` XS.get
maybe (return ()) (io . hClose) mh
xmproc <- spawnPipe "/usr/bin/xmobar /home/tony/.xmobarLrc"
XS.put $ XMobarHandle (Just xmproc)
)
You can create a function for the do block in the binding if you like. The binding for the other key is left as an exercise!
To make it compile, you still need the import statements for the modules used in this code. (I may have forgotten one, though!)
import XMonad.Util.Run
import System.IO
import qualified XMonad.Util.ExtensibleState as XS
You have to edit your logHook as well. There you have to extract the handle from extensible state just like in the keybind and give it as a parameter to the function xmobarlog.
I'm using the aeson package. I have a datatype which uses Data.Tree in its declaration. Like the following, only more complex:
data Foo = Foo {
bat :: Text
, xux :: Maybe Text
, tri :: Tree Text
}
I want to use Data.Aeson.TH to generate a FromJSON instance for this type.
$(deriveJSON defaultOptions ''Foo)
But Data.Tree does not have a standard instance for FromJSON, meaning that I would need to declare an orphan instace.
Is there some way to avoid creating that orphan instance, while still being able to use deriveJSON?
In order for an instance to be canonical (i.e. not an orphan), it needs to be defined in the same module as either the type constructor (Data.Tree) or the class declaration (Data.Aeson.Types). So the only way to define a non-orphan instance would be to fork aeson (since aeson depends on containers).
I'd recommend filing a ticket with aeson, or possibly a pull request, to get it added upstream. Until then, if you don't plan to distribute the code, defining an orphan instance shouldn't cause much trouble. If you're working on code you want to publish, the safest solution is to create a newtype wrapper around Tree, then make a FromJSON instance for the newtype.