|
Hi Scala users, How do I declare fields inside a try/catch inside a primary constructor?
Cheers, -John
|
|
Use something like this:
val y = try { "y" } catch { ... } Tony
On 18/01/2011, at 11:20 AM, John Ky wrote:
|
|
Hi Tony,
That works. How about if I have lots of fields and want to share the same catch clause for all of them? Cheers, -John
On 18 January 2011 11:28, Tony Sloane <[hidden email]> wrote:
|
|
You could attempt something like:
val (x,y) = try { ("x","y") } catch { ... } but then it's getting much more obscure. Tony On 18/01/2011, at 11:35 AM, John Ky wrote: Hi Tony, |
|
In reply to this post by John Ky
On Tue, Jan 18, 2011 at 11:35:58AM +1100, John Ky wrote:
> That works. How about if I have lots of fields and want to share the > same catch clause for all of them? The present possibilities are fairly unfortunate, but I have some good stuff in 2.9. Write a fancy catch block once (or a fancy catch block creating function) and reuse it. Off the cuff: object Test { def handler[T](value: T): PartialFunction[Throwable, T] = { case x: NullPointerException => println("NPE") ; value case x: Exception => println(x) ; value } // drink in the beauty of the braces which do not exist val x = ( try sys.error("oops") catch handler(5) finally println("fin") ) val y = try null.toString catch handler("NPE") def main(args: Array[String]): Unit = { } } // output % scala29 Test java.lang.RuntimeException: oops fin NPE -- Paul Phillips | It's better to have gloved and tossed than never to Protagonist | have played baseball. Empiricist | i pull his palp! |----------* http://www.improving.org/paulp/ *---------- |
val y = try null.toString catch handler("NPE") |
|
On Tue, Jan 18, 2011 at 12:01:59PM +1100, Ken Scambler wrote:
> Oh that is nice. Repetition in catch blocks was always a big problem > in Java. Does it work with finally as well? It always did. -- Paul Phillips | Simplicity and elegance are unpopular because Analgesic | they require hard work and discipline to achieve Empiricist | and education to be appreciated. all hip pupils! | -- Dijkstra |
|
In reply to this post by Paul Phillips-3
Hi Paul,
That sounds quite alright. However, the use case I was struggling with is something like this:
If an exception is thrown anywhere in the constructor, I need to close any resources already opened, so something like this:
Or if I write a Closer class, which represents a list of objects to close, I can reduce it to this:
Can I do any better? Cheers, -John
On 18 January 2011 11:55, Paul Phillips <[hidden email]> wrote:
|
|
On Tue, Jan 18, 2011 at 12:09:38PM +1100, John Ky wrote:
> That sounds quite alright. > > However, the use case I was struggling with is something like this: Yes, I am familiar. https://lampsvn.epfl.ch/trac/scala/ticket/3851 "Scope of variables declared in try block should extend to catch and finally" I supported doing something (if not necessarily what was proposed) but it was wontfixed. So I'm not aware of anything beyond what you see on the table. -- Paul Phillips | The most dangerous man to any government is the man who In Theory | is able to think things out [...] Almost inevitably he Empiricist | comes to the conclusion that the government he lives under ha! spill, pupil | is dishonest, insane, intolerable. -- H. L. Mencken |
|
In reply to this post by John Ky
I wrote a library (scala-arm) to help with this. You may be particularly interested in the delimited continuations API.
I think trying to access resources in the catch block may perhaps be 'the wrong thing' because you need to null check everything to ensure there was no error before accessing this resource. Using the ARM library, you can be assured that resources are closed in the inverse order they were opened, and that they are closed.
The basic usage works similar to your above closer idea, except you defer the opening of the resource block to for expressions. val a = managed(Resources.open()) val b = managed(Resources.open())
//Later for { a_ <- a b_ <- b } yield doSomethingAndReturn(a_,b_) // or for (a_ <- a; b_ <- b) { doSomething(a_,b_) }
Hope that helps! - Josh On Mon, Jan 17, 2011 at 8:09 PM, John Ky <[hidden email]> wrote: Hi Paul, |
|
In reply to this post by John Ky
Unfortunately, your code creates a couple of useless private tuple fields to hold the temporary.
But ... this doesn't seem like a very good approach to your use case. You might consider having a subclass of Resource that represents a failure to allocate a resource, including info about why -- it might even just be a wrapper for an Exception resulting from attempting to open the resource. Then you can just check to see if any of a,b,c,d contains such a failure. One possibility is Resource.needAll(rs: Resource*) that checks to see if any of its arguments represents a failure and if so closes the others and then throws an Exception (the thrown Exception should do the appropriate method overrides to combine the info of the failing cases); then you could simply write
There are numerous other straightforward possibilities once you abandon the control mess created by throwing Exceptions and return failure instances instead. -- Jim
On Mon, Jan 17, 2011 at 5:09 PM, John Ky <[hidden email]> wrote: Hi Paul, |
|
On Mon, Jan 17, 2011 at 7:32 PM, Jim Balter <[hidden email]> wrote:
> There are numerous other straightforward possibilities once you abandon the > control mess created by throwing Exceptions and return failure instances > instead. Scalaz is great for that kind of thing. this is probably almost compilable (lots of examples floating around out there): def open(): ValidationNel[Throwable, Result] = try { Resource.open().successNel } catch { e => e.failNel } (open() |@| open() |@| open())(new Foo(_,_,_)) will return either a Success(Foo) or a Failure(NonEmptyList(exception1, exception2,...)) -- Derek |
|
In reply to this post by Jim Balter-2
Hi Jim,
That's an interesting concept, however, doesn't it mean that if a fails then b, c, and d will still be created only to be discarded?
Also Resource.needAll is called from the primary constructor. However the primary constructor can't be used to return values. Doesn't it mean Resource.needAll must communicate errors by throwing an exception and as a result is contrary to the practise of returning error values?
i.e. I can't then compose Foo into Goo:
class Goo { val a = new Foo()
val b = new Foo() val c = new Foo()
val d = new Foo() Foo.needAll(a, b, c, d)
} because Foo doesn't follow the suggested coding style.
Cheers, -John
On 18 January 2011 13:32, Jim Balter <[hidden email]> wrote: Unfortunately, your code creates a couple of useless private tuple fields to hold the temporary. |
|
On Mon, Jan 17, 2011 at 7:37 PM, John Ky <[hidden email]> wrote:
Hi Jim, Yes, but is this a valid objection or is it premature optimization? In your version, a, a and b, or a and b and c will be created only to be discarded if the later allocations fail. And if an earlier allocation fails because of a lack of resources or other persistent error, then the later ones will too and so they won't be created only to be discarded. If Resource.open takes parameters and a, b, c, and d are independent, then you might well want to know their failure conditions independently -- e.g., if I try to concatenate four files, I would consider it a feature to report *all* of those that can't be opened and why, rather than reporting on only the first failure. And if a, b, c, and d aren't independent, then presumably the later allocations will fail because the earlier ones did. But if you really really need to optimize the failure cases, Resource.open could take a Resource* that is checked before allocation, returning failure if any of them were failures: class Foo { // each is only allocated if all of the preceding succeeded val a = new Resource.open()
val b = new Resource.open(a,b)
val c = new Resource.open(a,b,c)
val d = new Resource.open(a,b,c,d)
if( d.failed ) Resource.closeAndThrow(a,b,c,d) // among other possibilities
}
If you want a return value, use a factory method, as you did with Resource.open. A private constructor would throw the exception, which would be packaged into a failure instance by the factory method. If you call Foo's factory method "apply", you can simply omit the "new"s above. -- Jim On 18 January 2011 13:32, Jim Balter <[hidden email]> wrote: Unfortunately, your code creates a couple of useless private tuple fields to hold the temporary. |
|
In reply to this post by Jim Balter-2
Hi Jim, Oh - there it is: $ javap -classpath . -private Foo Compiled from "Hello.scala"
public class Foo extends java.lang.Object implements scala.ScalaObject{ private final scala.Tuple2 x$1;
private final java.lang.String x; private final java.lang.String y; public java.lang.String x();
public java.lang.String y(); private final scala.Tuple2 liftedTree1$1(); public Foo();
} I was a little unsure about it because I didn't see it here: $ scalap -classpath . -private Foo
class Foo extends java.lang.Object with scala.ScalaObject { def this() = { /* compiled code */ }
val x : java.lang.String = { /* compiled code */ } val y : java.lang.String = { /* compiled code */ }
} Factory methods it is then. Cheers, -John
On 18 January 2011 13:32, Jim Balter <[hidden email]> wrote: Unfortunately, your code creates a couple of useless private tuple fields to hold the temporary. |
|
In reply to this post by Derek Williams
On Mon, Jan 17, 2011 at 7:01 PM, Derek Williams <[hidden email]> wrote:
That's a nice approach. Foo could have a private constructor that takes Resources that have already been opened. object Foo's apply method would do the one-liner. It's all quite composable. Too bad Scalaz is so short on documentation. |
|
In reply to this post by Derek Williams
Hi Derek,
Took me a while to digest it, but some nice concepts there so thank you. Cheers, -John
On 18 January 2011 14:01, Derek Williams <[hidden email]> wrote:
|
|
In reply to this post by John Ky
Hi all,
It just occurred to me I could have defined my Disposer class to do all the necessary catching and rollback thus:
This means allows me to define my Foo class like so:
Because the disposes method now takes a function returning a disposable value rather than the disposable value itself, the Resource.open() is called from within the disposes method where it can be caught and a full roll back of allocations can be triggered transparently.
It does mean my Foo class has an extra disposer field, but as it turns out, that isn't so bad because the field lets me define my Foo.dispose method in one line:
So it was convenient to have it around anyway. Cheers, -John On 18 January 2011 11:20, John Ky <[hidden email]> wrote:
|
| Powered by Nabble | Edit this page |
