ideas-computer-jasper-jasperErrorNotes1

"Error messages from Complex types

In Yesod we have some complex types in a few key places. And we are fine with having complex types internally. However, exposing them in an interface is a very delicate matter- users have to be able to understand error messages. Yesod has abandoned certain uses of polymorphism due to this issue. And we would still like to make error messages better.

Reading error messages is an interface through which programmers learn Haskell. Is there a way to make error messages better? The most interesting approach I can think of is to somehow let the library writer specify certain error messages. "


ArgumentCheckingException?:

--

http://docs.python.org/2/library/exceptions.html

--

interesting Scala idiom:

scala Options (like Haskell maybes) are implicitly coerced to sequences with zero elements (for None) or sequences with one element (for Some), allowing you to use flatMap (which is like concat(map())), to take a sequence, map over it producing a sequence of Options, and return only a sequence of the valid elements, e.g.

scala> val l = List(1,2,3,4,5) scala> def f(x: Int) = if (v > 2) Some(v) else None

scala> l.map(x => f(x)) res66: List[Option[Int]] = List(None, None, Some(3), Some(4), Some(5))

scala> l.flatMap(x => f(x)) res67: List[Int] = List(3, 4, 5)

-- http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/

--

http://250bpm.com/blog:4

 Why should I have written ZeroMQ in C, not C++ (part I)

--

http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758

--

"

If that wasn’t bad enough, not all Java exceptions are checked, subclasses of java.Error and java.RuntimeException? are unchecked. You don’t need to declare them, just throw them. This probably started out as a good idea, null references and array subscript errors are now simple to implement in the runtime, but at the same time because every exception Java extends java.Exception any piece of code can catch it, even if it makes little sense to do so, leading to patterns like

catch (e Exception) { ignore }

"

--

" Might I even suggest going one step further and stealing the fail/succeed/cut mechanism from Icon. Go with goal-direction would be a thing of genuine beauty. "

--

http://lambda-the-ultimate.org/node/3896

--

my take on golang's exceptions: i agree with Tom Lord, the current way that Go does things is just exceptions under another name, except that 'defer' is more syntactically flexible than a 'catch' block, and except that the defer/panic/recover mechanism is slightly more confusing, esp. the way that all 'defers' are like 'finally' so you have to check 'recover' within your defer to see if you are panicing, and also because you cannot match the exceptions against a pattern in the 'defer' declaration like you can with a 'catch' block

i guess one good thing about them is that panic/recover is not a syntactic control structure.

since pattern-matching guards will be an integral part of jasper, mb we can make a 'catch' without core language support

--

Dylan's exception system looks pretty good:

--

if exceptions are (mis?)-used to report expected errors, esp. errors which the caller might want to accumulate, and if scope-based resource release is in play, then the exception will release the resource even though we might have wanted to continue (alternately, the scope-based resource relase cannot be used, which is a pain):

http://stackoverflow.com/a/1744176/171761

--

" In fairness to Go, exception handling is much trickier when you live in a world of lightweight co-routines. But again, Erlang seems to generalize things in a plausible way: Declare links between co-operating processes, and propagate failures across those links until somebody wants to catch them and recover. "

" Also Haskell seems to discourage exceptions. They are possible to raise everywhere and catchable in the IO Monad --- but they do not play along nicely. It's often better to wrap up your error handling in a Maybe or Either or Error Monad. (In level of increasing sophistication.) "

---

i like the notation in the guy with the atom avatar's proposal from https://groups.google.com/forum/#!topic/golang-nuts/SskXyc9D5Sk

that is, for every Maybe type T, #T is the Just type. So #(Maybe Int) = Int

and you'd also want to add the reverse operator @V, that could take a plain type and create a Maybe: @Int = Maybe Int.

of course you don't really need @ as Maybe Int is almost as ez to write.

--

hmm.. golang has a strong convention that panic never crossed module boundaries, e.g. if you are using someone else's API you don't have to worry about panics.. could enforce that by the compiler to say that only checked exceptions may cross module boundaries.. don't make it part of the type so that you don't have the versioning problem of checked exceptions.. but wait if an underlying library throws an exception then you have to change your declaration, right? maybe you can just specify a superclass or set of superclass that covers all exceptions that you might throw, e.g. throws Exception, and that is good enough...

but i like exceptions..

--

http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors/ http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/ http://book.realworldhaskell.org/read/error-handling.html

---

this presentation http://www.slideshare.net/olvemaudal/deep-c (and comments) show several places where C and C++ use a different design criterion than Python's "refuse the temptation to guess". E.g.:

printf( a, b); }

also, if the standard says that source code must end with a newline, that's a bit silly imo

also, the presentation says "C has very few sequence points.This helps to maximize optimization opportunitiesfor the compiler." -- this is a tradeoff of optimization vs. principal of least surprise.

also, if you have a variable defined outside any function, it is statically allocated whether or not it has the 'static' keyword. but now the 'static' keyword is used as an access modifier to define visibility to other compilation units in the linker! 'static' means 'local to this compilation unit, not visible in this linker', and the default is 'visible to the linker, can be accessed from other compilation units'! this is confusing!

---

as far as 'refuse the temptation to guess' goes, otoh it was mighty frustrating when my logging or debugging code crashed my Python program just becuse the user had passed in Unicode but the debugging code just used "print x" (instead of "print repr(x)" which would have worked) in the logging or error-handling code, and since i hadn't set the (charset on stdout? i dont remember what i hadn't set) Python crashed when a non-ASCII character was printed.

two notes there: * 'refuse the temptation to guess' when you can catch an error at COMPILE TIME, not necessarily runtime * having str(x) be the implicit conversion, and having str(x) be unsafe while repr(x) is safe, is a bad idea. In fact, i might say that implicit type conversions should not be able to fail at runtime * we might want 'refuse the temptation to guess' be a compiler flag/section flag which is turned off in debug sections

---

we want ppl to be able to try to access a memory location and to get a maybe return type that is Nothing if accessing it would be a segfault, and a Just if the access works (or we could use exceptions, which also works for writes). on x86 platform i dont think this is direcly possible, i think the only way to figure out if something would segfault is to segfault, and then it messes up that thread permanently ( http://stackoverflow.com/questions/1955347/is-there-a-point-to-trapping-segfault ) but i think you can spawn another thread and do the memory access in that thread.

anyhow, spawning this other thread is the right thing to do but it's high-overhead. so we'd like to allow the programmer to tell us not to do it. this should be in the form of a promise that the result of accessing the memory is always a Just and never a Nothing.

so we'd need cheap syntactic sugar for promising that. Also, the routine doing the read needs to be able to ask if the result it is giving is promised to be a Just.

--

mb the doctrine should be: use Just/Nothing for pure things (like reads, computations), and use exceptions for failed mutations only.

--

need to be able to subclass Nothing to specify fine-grained error conditions in a way that allows old/ignorant code to still treat it as a normal Just/Nothing.

--

" The second observation is something I had not previously considered. In C there is no exception handling. If, as in the case of extsmail, one wants to be robust against errors, one has to handle all possible error paths oneself. This is extremely painful in one way - a huge proportion (I would guess at least 40%) of extsmail is dedicated to detecting and recovering from errors - although made easier by the fact that UNIX functions always carefully detail how and when they will fail. In other words, when one calls a function like stat in C, the documentation lists all the failure conditions; the user can then easily choose which errors conditions he wishes his program to recover from, and which are fatal to further execution (in extsmail, out of memory errors are about the only fatal errors). This is a huge difference in mind-set from exception based languages, where the typical philosophy is to write code as normal, only rarely inserting try ... catch blocks to recover from specific errors (which are only sporadically documented). Java, with its checked exceptions, takes a different approach telling the user "you must try and catch these specific exceptions when you call this function".

What I realised is that neither exception-based approach is appropriate when one wishes to make software as robust as possible. What one needs is to know exactly which errors / exceptions a function can return / raise, and then deal with each on a case-by-case basis. While it is possible that modern IDEs could (indeed, they may well do, for all I know) automatically show you some of the exceptions that a given function can raise, this can only go so far. Theoretically speaking, sub-classing and polymorphism in OO languages means that pre-compiled libraries can not be sure what exceptions a given function call may raise (since subclasses may overload functions, which can then raise different exceptions). From a practical point of view, I suspect that many functions would claim to raise so many different exceptions that the user would be overwhelmed: in contrast, the UNIX functions are very aware that they need to minimise the amount of errors that they return to the user, either by recovering from internal failure, or by grouping errors. I further suspect that many libraries that rely on exception handling would need to be substantially rewritten to reduce the number of exceptions they raise to a reasonable number. Furthermore, it is the caller of a function who needs to determine which errors are minor and can be recovered from, and which cause more fundamental problems, possibly resulting in the program exiting; checked exceptions, by forcing the caller to deal with certain exceptions, miss the point here. "

---

doug: > consider a coalescing operator rather than > unwrapping. first ?? 0 = first if first is not null, otherwise 0.

yeah i want an operator like that. i have a reminder written somewhere to put one in, i'll write a second reminder so i don't forget.

---

[Python-ideas] Please reconsider the Boolean evaluation of midnight Shai Berger shai at platonix.com Wed Mar 5 11:16:12 CET 2014

    Previous message: [Python-ideas] Python Numbers as Human Concept Decimal System
    Next message: [Python-ideas] Please reconsider the Boolean evaluation of midnight
    Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

Hi all,

This is my first post here, following a recommendation from Alexander Belopolsky to use this list, to try to convince the Python developers to reopen a ticket. I am a long-time Python user, and a Django committer.

http://bugs.python.org/issue13936 is a complaint about the fact that midnight -- datetime.time(0,0,0) -- is evaluated as False in Boolean contexts. It was closed as invalid, under the claim that """It is odd, but really no odder than "zero values" of other types evaluating to false in Boolean contexts""".

I would like to ask for this to be reconsidered; since the ticket was closed, two main arguments were given for this:

1) The practical argument (paraphrasing Danilo Bergen and Andreas Pelme): The current semantics is surprising and useless; users do not expect valid times to be falsey, and do not normally want code to have special behavior on midnight. Users who ask for Boolean evaluation of a variable that's supposed to hold a time value, usually write "if var" as shorthand for "if var is not None".

2) The principled argument (which I think is at the root of the practical argument); quoting myself from the ticket: """Midnight is not a "zero value", it is just a value. It does not have any special qualities analogous to those of 0, "", or the empty set. ... Midnight evaluting to false makes as much sense as date(1,1,1) -- the minimal valid date value -- evaluating to false""".

Thanks, Shai.

---

clarkevans 2 days ago

link

INADA Naoki's argument [1] is succinct and insightful.

  I feel zero value of non abelian group should not mean
  False in bool context.
  () + () == ()
  "" + "" == ""
  0 + 0 == 0
  timedelta() + timedelta() == timedelta()
  time() + time() => TypeError

[1] https://mail.python.org/pipermail/python-ideas/2014-March/02...

reply

StefanKarpinski? 2 days ago

link

This is a nice clean criterion, but it's still pretty unclear to me why the zero element of a monoid should be considered falsey at all.

reply

chrismonsanto 2 days ago

link

Because when writing a recursive function, the zero element is generally the base case.

    if x:
        <destructure x, recurse on subparts>
    else:
        return <something>

This applies to (natural) numbers as well--'destructuring' usually means decrementing the number.

reply

dalke 2 days ago

link

If that were true, it would mean that dict should not support bool:

    >>> {} + {}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
    >>> bool({})
    False

Since I find bool(a_dict) to be very useful, and the lack of a_dict+b_dict to be reasonable (precisely because it's non-abelian!), I conclude that logic is cute, but not that relevant.

Those who think it this argument is pursuasive, should bool({}) raise an exception? Or should {1:"A"}+{1:"B"} not raise an exception and instead return ... what?

Or do I misunderstand something?

reply

baddox 1 day ago

link

Honestly, I would be fine with nothing supporting bool, and requiring `if` conditions to be bools. Arrays and dictionaries could have methods like `.empty?` that return a bool. Strings could have `.blank?`. Obviously, I'm stealing the methods from Ruby, although Ruby also has its own notions of truthiness of non-booleans.

reply

dalke 1 day ago

link

There are many languages which do something like that. Python is not one of them. Personally, I find it useful to write things like "if x:" and not worry about if x is None or x is s list of characters or x is a string of characters.

reply

--

what is so annoying about writing latex documents? it's that you shouldn't have the possibility of a compilation error when you are just trying to write a document. so this is perhaps one case in which you'd prefer the compiler to recover upon an error instead of crashing upon an error. you'd want to latex document to insert a 'i dont understand this construct' and to still show the rest. but how to do that?

perhaps erlang can give us some clues, since they seem to have a system where processes can crash but this is isolated from the rest of the system, which keeps on ticking.

--

on Java's new Optional:

rat87 1 day ago

link

...

There's no equivalent of scala's orElse(returning a second optional if the first one is null) and since default methods while useful don't allow adding things to types you don't own you can't use an method like notation for the best you can get is static importing and wrapping a function around it). ofNullable(creating an empty Optional from a null instead of throwing) isn't the default(of which throws is). Also Optional isn't an Iterator which is disappointing since using it with a for loop can be useful if you want to avoid nested closures.

meddlepal 2 days ago

link

My problem with Optional<T> is that it basically makes overloaded Java methods impossible because of erasure. I'm worried that it is going to start getting overused; the JDK developers really only intended for its use in the Streams API.

reply

tel 2 days ago

link

Could you explain that a little bit more? I'm using to Maybe from Haskell and am curious what might be missing from Java's Optional.

reply

matwood 2 days ago

link

Basically, because of type erasure you cannot have overloaded methods using different Optional types. So test(Optional<A> a); is the same method as test(Optional b);

I think you can define the types to get around it, but that is messy and a PITA. For example, class OptionalA? extends Optional<A>.

reply

tel 2 days ago

link

That doesn't seem so bad to my eye, though. In Haskell terms it just means that any overloaded operators on Optional have to respect parametricity. If you need something more specifically typed then you can just use a new name.

Is there a particular use case?

reply

tomp 2 days ago

link

Btw, type erasure is only a problem for Java because it supports runtime type information (which is incomplete, because of type erasure), and overloading (which I have no idea why the compiler can't handle). For languages like ML and Haskell, type erasure is no problem, because you can't access the types at runtime anyways.

reply

dignati 2 days ago

link

Wow that's a real pain point. Why would they even do that, is there a use case?

reply

im3w1l 2 days ago

link

In my opinion, no it really isn't. You can just create a method with a different name or a static constructing method if you need to overload constructors.

The major pain point with generics is that they don't work with primitives.

reply

im3w1l 2 days ago

link

Because of type erasure, all Optional<T> are the same type at runtime, so Optional<Integer> can't be overloaded with Optional<Boolean>, because at runtime it will be impossible to tell which method should be caled.

reply

matwood 2 days ago

link

For those still on pre Java 8, Google's Guava also adds Optional and other useful things like immutable collections.

reply

maaaats 2 days ago

link

And now frameworks can finally supply Optionals, since it before only lead to multiple competing implementations.

reply

mike_hearn 2 days ago

link

But is it really better than @Nullable?

reply

jburwell 2 days ago

link

Completely different concepts. @Nullable expresses an precondition indicating whether or not something can be null. One example of its use is by static analyzers such as Findbugs to find misuse to APIs. In contrast, Optional encapsulates the behavior when something is not present (or null) -- very similar to the Null Object pattern [1]. Used together, you can build an API that permits encapsulates the present/not present behavior and ensure that it is not passed a null reference to the Optional instance.

[1]: http://en.wikipedia.org/wiki/Null_Object_pattern

reply

vog 2 days ago

link

It is a pity that Qt is not mentioned in that article. AFAIK, It is the only widely-used C++ library that implements null objects consequently. Ever wondered why the Qt framework doesn't use any exceptions or C-style error codes? It is solely because of proper use of Null objects.

reply

hutteman 2 days ago

link

I would say in most cases: no.

Due to backwards compatibility concerns, no existing Java APIs that may currently return null can ever be changed to return Optionals instead, so nulls need to be dealt with regardless. Also, there's technically nothing stopping an Optional value from actually being null itself, or from developers calling Optional.get() without checking isPresent(), just like they might currently use a reference without checking for null.

I personally really wish jsr305 had been adopted in Java8, and their existing APIs retrofitted with these annotations.

http://www.oracle.com/technetwork/articles/java/java8-option... describes Optional, and compares it to how in Groovy, the safe navigation and elvis operators allow you to write code like this:

   String version = computer?.getSoundcard()?.getUSB()?.getVersion() ?: "UNKNOWN";

With Java 8 Optionals, this instead becomes:

   String version = computer.flatMap(Computer::getSoundcard)
                            .flatMap(Soundcard::getUSB)
                            .map(USB::getVersion)
                            .orElse("UNKNOWN");

which is not only much longer and arguably uglier, but also forces developers to suddenly have to worry about applying lambdas using flatmap vs map, where conceptually you're really just dealing with method calls.

New languages like Kotlin solve this much better in my opinion by introducing nullable vs nonnullable types. While Java can unfortunately never adopt this due to backwards compatibility issues, @Nullable and @Nonnull will do most of the time, and hopefully we'll see operators like ?. and ?: in future versions of Java.

reply

hibikir 2 days ago

link

While I've enjoyed the Elvis operator in Groovy, the point of optional is to make null go away altogether. In Groovy, you are never guaranteed anything isn't null, so the end result is that you will Elvis everything. While this is easier than the good old if statements, you are still paying for the penalty of a billion ifs in bytecode.

With option, you clearly declare what is safe, and what isn't, and the compiler won't let you screw up. You can decide which layer of your code handles the empty case, and lots of unnecessary ifs go away from the bytecode itself, so the app will run faster, and you know when you have to even consider the null case.

Now, doing that in Groovy is rather silly, because your language is dynamic and your types are optional, so all of this compile time safety would not provide any value anyway. Option is just the way you'd solve the problem in the strongly typed way. It's how you handle it in Scala, for instance, and how Haskell would deal with it.

As far as using flatmaps and maps to work with optionals, yes, it's a chore. I'd argue it's borderline abuse of the stream operators, as treating Option as a collection is ugly. That said, putting yourself in a situation where you chain 3 optional getters is also object design from hell, so one should avoid putting themselves in that position altogether.

In Scala, instead of flatmapping single optionals, we often getOrElse(), or use pattern matching as an extractor. Now that's a feature I would like to see Java 'steal' from the Scalas and Erlangs of the world, but I do not see that happening.

reply

vorg 1 day ago

link

> in Groovy, the safe navigation and elvis operators

The elvis op is called the null coalescing op in other languages. [1] Groovy's promoter chose the elvis name to fit in with marketing the Groovy and G-String names.

PHP also uses the ?: symbol but other languages use different ones, e.g. C# uses ?? and Perl uses

[1] http://en.wikipedia.org/wiki/Null_coalescing_operator

reply


if an exception handler wants to 'resume', then the error condition which caused the exception should be rechecked. But then we also need an infinite-loop detection that does not recheck it more than once (unless this loop detection mechanism is explicitly overridden).