Progress.lang.error

Posted by jmls on 11-Sep-2008 16:49

According to the documentation, this class is an interface, which Progress.lang.Proerror implements.

If it is an interface, how does the following code work ? (I've got a really bad feeling that I'm being stupid about this)

CATCH e AS Progress.Lang.Error :

MESSAGE "error:" e:getmessage(1) VIEW-AS ALERT-BOX.

DELETE OBJECT e.

END CATCH.

as far as I was aware, an interface cannot define the contents of a method, only that a class must implement such a method.

So, how does e:getmessage(1) actually work ?

All Replies

Posted by Admin on 11-Sep-2008 17:03

as far as I was aware, an interface cannot define the

contents of a method, only that a class must

implement such a method.

That's right. It's abstract.

So, how does e:getmessage(1) actually work ?

e is defined as a variable of the Interface type. This way I can call the methods defined in the Interface - and only the methods defined in the Interface.

That's normal behaviour. The whole concept of Interfaces would be useless if I could not call methods of classes implementing the Interface on a variable of the Interface type.

In a way the Interface is like a SUPER class (without implementation). If you only have a reference of a SUPER class (base.Entity or Progress.Lang.Object or System.Control) you only have access to the members defined in that base class.

You need to CAST to another type in order to get access to more members.

Posted by jmls on 11-Sep-2008 17:06

That's right. It's abstract.

ok ...

e is defined as a variable of the Interface type.

This way I can call the methods defined in the

Interface - and only the methods defined in the

Interface.

ok ...

That's normal behaviour. The whole concept of

Interfaces would be useless if I could not call

methods of classes implementing the Interface on a

variable of the Interface type.

but if e is an interface, the method GetMessage does not have any implementation. So how can it actually return some data ?

See, I told you I was feeling stupid ...

Posted by Admin on 11-Sep-2008 17:09

but if e is an interface, the method GetMessage does

not have any implementation. So how can it actually

return some data ?

e is an instance variable of an Interface type. The compiler only knows about the methods defined in the Interface. Everything else is hidden.

But at runtime it points to an actual instance of a concrete type. So there must be an implementation for GetMessage and others. That is garanteed!

Posted by Admin on 11-Sep-2008 17:15

See, I told you I was feeling stupid ...

OO is much more than substituting Procedure statements with method statements. That shift must make you feel stupid. I felt like learning coding again.

Posted by jmls on 11-Sep-2008 17:15

e is an instance variable of an Interface type. The

compiler only knows about the methods defined in the

Interface. Everything else is hidden.

That I understand

But at runtime it points to an actual instance of a

concrete type. So there must be an implementation for

GetMessage and others. That is garanteed!

But where is the implementation implemented ? If I wanted to try to duplicate this, I would first create an interface class foobar.

USING Progress.Lang.*.

INTERFACE foobar:

METHOD PUBLIC LOGICAL foo():

END INTERFACE.

if I were then to say

DEF VAR a as foobar.

message a:foo() view-as alert-box.

what would it do ?

I guess what I am trying to get at is

where is the code that retrieves the message stored at position 1 in the GetMessage(1) method of the progress.lang.error interface ?

Posted by Admin on 11-Sep-2008 17:20

where is the code that retrieves the message stored

at position 1 in the GetMessage(1) method of the

progress.lang.error interface ?

Aaah! We are getting to the point. Where is the FOR EACH implemented?

I'd say it's sealed in some safe place in the woods of Bedford or Nashua. The core objects like the error classes/interfaces, Progress.Lang.Object, Progress.Lang.Class, Progress.Data.BindingSource, etc. are part of the C code that make the Progress client.

That's not given to us. They cheat on us a little bit Or protect us from the dirty bits.

Posted by jmls on 11-Sep-2008 17:20

Oh, and another thing !

Why can you do

NEW AppError("foo") /* message only */

NEW AppError("foo",1) /* message and severity */

but you can only do

AddMessage("bar",0)

why isn't there an override

AddMessage("foo")

Posted by Admin on 11-Sep-2008 17:22

what would it do ?

Output a >runtime

You need to NEW a - between DEF VAR and a:foo() .

a = NEW SomeTypeThatImplementsFoobar () .

Posted by Admin on 11-Sep-2008 17:24

NEW AppError("foo") /* message only */

Did you read the docs?

The constructor with the single character parameter does not set an error message. It set's the RETURN-VALUE attribute of the AppError.

Posted by jmls on 11-Sep-2008 17:24

That's not given to us. They cheat on us a little bit

Or protect us from the dirty bits.

So, it's exposed to us as an interface, but in the background there is an object created called progress.lang.error that implements the interface progress.lang.error ?

Posted by jmls on 11-Sep-2008 17:25

yup, I knew that. I was being a devil's advocate.

Posted by Admin on 11-Sep-2008 17:25

Error Messages always need the integer message number.

Posted by jmls on 11-Sep-2008 17:26

Did you read the docs?

Several times. My head hurts

The constructor with the single character parameter

does not set an error message. It set's the

RETURN-VALUE attribute of the AppError.

Thanks.

Posted by jmls on 11-Sep-2008 17:28

Ok, so if I wanted to add a message with just the text, I would create a new class inheriting apperror, and add the following method.

METHOD PUBLIC VOID AddMessage(p_message AS CHAR):

SUPER:AddMessage(p_message,0).

RETURN.

END METHOD

Posted by Admin on 11-Sep-2008 17:30

Not exactly. The actual error object is not a Progress.Lang.Error. It's of one of the types implementing the Progress.LangError.

Progress.Lang.SysError for instance.

Posted by Admin on 11-Sep-2008 17:32

Exactly. And you could add a lot more here. You could add translation, persistent logging etc.. Anything that itself does not raise a runtime error.

Posted by jmls on 11-Sep-2008 17:39

Not exactly. The actual error object is not a

Progress.Lang.Error. It's of one of the types

implementing the Progress.LangError.

Progress.Lang.SysError for instance.

urk, ok, I surrender (give up)

Posted by jmls on 11-Sep-2008 17:41

Exactly. And you could add a lot more here. You could

add translation, persistent logging etc.. Anything

that itself does not raise a runtime error.

Yeah, done that already - it's really handy. I'm doing a workshop soon on error handling and it's a really great example on how to use the new stuff.

thanks for the additional info.

Posted by Thomas Mercer-Hursh on 11-Sep-2008 18:51

urk, ok, I surrender (give up)

Does that mean the light bulb went on or that you were overwhelmed.

If the latter, step back for a moment from the context of error handling and consider how interfaces get used in the general sense. Suppose I have three classes A, B, and C which all implement interface I. I've got some code which might instantiate any one of these three depending on circumstances. Then, I hand over the object I have instantiated to somewhere else which doesn't know which of the three it is. I can do this because I can define the local variable containing the class as the interface. That let's me get at the common methods that are defined in the interface, but I have to cast it to the right type in order to get at the rest. This is similar to defining the variable as a superclass, using methods in the superclass, and then casting to the subclass when it becomes necessary, only by using an interface the classes don't need to be in the same class hierarchy.

So, in the error handling context, the place the error is thrown is creating an object of a specific type, but we don't necessarily know what type. What we do know, however, is that it will implement the Progress.Lang.Error interface. So, that's what the type is of e.

There is a very standard philosophy in OO of "programming to the interface".

Posted by Admin on 11-Sep-2008 19:03

So, in the error handling context, the place the

error is thrown is creating an object of a specific

type, but we don't necessarily know what type. What

we do know, however, is that it will implement the

Progress.Lang.Error interface. So, that's what the

type is of e.

And then there are those occasions, where you'll prefer not to catch the Progress.Lang.Error everywhere, because you might prefer to handle different types of possible (expected in various locations) error types at different levels at your code.

Usually you'll handle the most expected error close to the location the error might occur because you actually might do something useful except to display a message.

The CATCH for Progress.Lang.Error will CATCH any error.When I expect errors from my routines, I usually catch for somethine that inherits from Consultingwerk.Exceptions.Exception (sorry, I could not resist to call it Exception).

And then you'll start to realize how nice it would have been if Progress would have created an error hierachy for runtime errors like in other pure OO languages. So to make efficient use of subclassing errors you need to create your own errors (inheriting AppError) and throw them whenever an expected runtime error (SysError) needs handling.

Posted by Thomas Mercer-Hursh on 11-Sep-2008 19:12

I think it would be very interesting to start sharing some examples of error handling code. It seems like an area where we could benefit by seeing what other people do.

This thread is closed