Came across the first problem in porting our application to 10.2A.
We initialize a single "session" class. In order to find out if we need to instantiate this class, we run through the session objects looking for the right class. The code snippet is :
DEF VAR SomeObject AS CLASS PROGRESS.lang.OBJECT NO-UNDO.
ASSIGN SomeObject = SESSION:FIRST-OBJECT.
FindSomeObject:
DO WHILE VALID-OBJECT(SomeObject):
IF SomeObject:getClass():TypeName EQ "myapp.library.sessionsingleton" THEN
DO:
ASSIGN SessionObject = CAST(SomeObject, "myapp.library.sessionsingleton" ).
LEAVE FindSomeObject.
END.
ELSE ASSIGN SomeObject = SomeObject:NEXT-SIBLING.
END.
IF NOT VALID-OBJECT(SessionObject) THEN /* load it */
The problem we came across was trying to run this program from the OEA . This problem manifested itself when the GetClass method returned ?.
Now, the help for GetClass mentions "This method does not apply to instances of .NET classes. If the current class is an instance of a .NET class, this method returns the Unknown value (?)."
So, this is expected behavior in 10.2A. The problem is that it breaks an existing system, and we would have to modify existing code to make this work, so it is not desirable behavior.
Could a flag / option be added to the GetClass method ? So that:
GetClass() or
GetClass(Progress) only looks at progress object(s)
GetClass(Net) only looks at .net objects
GetClass(ALL) looks at both sets
Message was edited by:
Julian Lyndon-Smith
fixed typo in typename
Isn't it the object chain that would require the parameter, rather than the GetClass method?
So that you get
SESSION:FIRST-OBJECT
or SESSION:FIRST-OBJECT(Progress)
...
and NEXT-SIBLING(Progress)...
That would make a lot more sense.
Hi Julian, are you aware that we have static data members since 10.1c? So instead of searching the one (and only) instance of the session class, you could either turn that sessionsingleton completly into a class with static methods and data members or use a static class to point to the instance of the session class (and launch it if required) instead of seeking it. This one static data member to return the sessionsingleton instance could probably as well be maintained in the sessionsingleton class itself.
Since the modification to the signature of the GetClass() method would also require some changes in your code, I guess a change to:
IF VALID-OBJECT(SomeObject:GetClass()) AND SomeObject:GetClass():TypeName EG "debtnet.library.sessionsingleton" ....
would not have a bigger impact to your code. Strucutred Error-Handling (an empty CATCH Progress.Lang.Error block) might be an option as well - but that depends on the structure of the remaining code.
Too mee that looks too much like creating to classes of objects. I like the fact, that .NET and ABL classes are handled (as close to each other) as possible.
Yeah, I was aware - however there is one of our clients who is still on 10.1B ...
possible the most robust change to your code, would be the use of the TYPE-OF function, instead of Querying the TypeName:
IF TYPE-OF (SomeObject, myapp.library.sessionsingleton) THEN ...
Please note, that there are no quotes to the Typename in the TYPE-OF function.
I like it as well - trouble is that it breaks an existing codebase, which is never a good thing.
I'm pretty sure, TYPE-OF was available in 10.1B as well
no, my reply "I like it as well" was referring to the comment you made about .net and progress classes being treated the same
Strictly speaking I think the existing codebase is not broken when moved to 10.2. The existing code doesn't use .NET objects so it will still run under 10.2.
Only when you start making changes to your application and add .NET objects to it the application will break. But if you can add .NET objects you can probably also make the required change to that code (except when you've only got xcode for that part of your application).
I beg to disagree - I cannot run my application from the OEA because of the visual designer .net class. So, even without using .net classes I have a problem.
I understand.
But if you like to stay with the same codebase for 10.1B and 10.2A development a change in the signature ot the GetClass method of the SESSION:FIRST-OBJECT property will work without changes to the code anyway. And those (new) parameters will not be available in 10.1B anyway.
So you really need to modify your code anyway for maintaining the backwards compatility. Either use error handling, the valid-object check of the TYPE-OF validation. All that (except structured error handling and statics) would work with 10.1B as well.
Is the class there when you've not started the designer yet? Although I do agree that it's undesirable and may very well be a significant problem for companies who have a large part of their application only as xcode and an uncoperative (or even no-longer existing) software vendor who wrote the code in the first place.
No I wouldn't have to change my code, because by default the GetClass() would return only progress objects, so the code would work under 10.1B and 10.2A
However, with the help from everyone here, I've modified the code to use TYPE-OF and committed the change to the 10.1B codebase problem no longer exists.
I really just wanted to highlight the fact that there was a problem with existing code not working as it did before.
I really just wanted to highlight the fact that there
was a problem with existing code not working as it
did before.
Without being too picky here. The code still works as it did before.
In 10.1B this was coded in the assumption, that any object belongs to a class and that this class can be queried using the GetClass() method of that object.
Now we have .NET objects in addition. They have a different way to return the type they belong to. That's why your code breaks. Not because a change in the behaviour of the ABL objects.
Heh. you and I obviously have a different opinion on "works as before"
if the same line of code works in 10.1B, but doesn't in 10.2A then I would claim that it "doesn't work as before"
If with 10.2A PSC changed the def var statement, so that
DEF VAR a AS CHAR.
doesn't compile anymore, as you need to say
DEF VAR a AS PROGRESS-CHAR.
instead.
would you still say that the code works as it did before, because they have a different way of defining a variable ?
He He. I like Friday afternoon threads
I would totally agree that this (CHAR to PROGRESS-CHAR) would be broken by 10.2A.
But using a chained reference without ensuring the validity of your code is not the fault of a new language feature - for my personal understanding.
How about this: SESSION:FIRST-PROCEDURE normally always returns a procedure handle, since progress clients need a startup procedure. What if that will ever be changed, so that a progress client can use a class (default constructor I guess) as it's startup procedure and you can code complely without the legacy of procedures.
I would not consider that broken by that (desirable) nice feature at all. It would be fault of all the times I did not check the validity of my chained object references (or used appropriate error handling).
In your case here, the only .NET object in memory was the visual designer. How about using a launch configuration in a separate progress runtime (a very cool feature in 10.2a). Then at least the visual designer should not interfer with your code.
Mike (from finally sunny Cologne)
Me too! Time for a beer thread ...
Under 10.1B, the ClassType() always returned a valid handle - it was, and is, documented that all progress objects have a class type. I would have been unaware that a couple of years later Psc would change the documented behavior (for very good reasons) by adding a different type of object into the chain and make my code not work.
I have been using that cool feature, but as mentioned earlier, I've fixed my code Took much less time to change the code than to discuss it in this thread !
Thanks for the help and points of view.
If Progress decided to make the default locking behavior NO-LOCK instead of SHARE-LOCK I would consider it a very desirable feature, however I don't think that will ever happen because it would break too many applications.
If exactly the same code runs under 10.1A and doesn't run under 10.2 compatibility is broken.
The question however when considering a significant change to avoid this break is:
- Can it be considered the same code when actually there's suddenly more code running.
- is the break significant enough to allow major changes, will it every cause real problems for a company or is it more a theoretic problem?
Progress can decide upon the answers
The example you gave about the SESSION:FIRST-PROCEDURE won't break existing applications, because every existing application has a startup procedure. It may not work in future applications which don't have a FIRST-PROCEDURE, but the existing applications will still run unchanged in the new progress version that supports a procedureless application.
Personally I think no change to the syntax is really desirable here (given the limited impact.) Mentioning the issue in the release notes or some other documentation would be enough.
Me too! Time for a beer thread ...
Under 10.1B, the ClassType() always returned a
valid handle - it was, and is, documented that all
progress objects have a class type. I would have been
unaware that a couple of years later Psc would change
the documented behavior (for very good reasons) by
adding a different type of object into the chain and
make my code not work.
I have been using that cool feature, but as mentioned
earlier, I've fixed my code Took much less time to
change the code than to discuss it in this thread !
Thanks for the help and points of view.
Man, just got bitten by this again. I've fixed it again (long story, I delete the branch of code I was using for 10.2A and recreated it from trunk) . But I still see no reason why I should have to modify existing code in order for it to work in 10.2A.
Hi Julian,
If you are not using .NET at all in your application, the object chain is expected to work as in previous releases, there should not be any .NET classes in your session. One of the ways to test this would be to make sure you use a run configuration with -noclr and launch your non-.NET application using that run configuration. In theory you should not need -noclr, its mainly to speed up compilation time.
If OEA thinks you are using the .NET it may have loaded .NET classes into the project's OpenEdge development session (used for compiling, etc). With OOABL it is a good idea to always run your application in a fresh session and not use this development session.
-Shelley
Shelley has a good point here. If you are using the AVM associated with a project to run your code, you need to be aware that you are operating in a polluted environment. OEA may at any time decide to run something on the project AVM or perform a compile and you may not be aware of it. Testing your code in this environment could lead to unexpected results.
The proper way to test/run is to use a separate AVM. Run configurations can help with this. If you are absolutely sure you are not using any .NET stuff in your project then you can you the -noclr option to disable the .NET functionality completely. This will prevent the VD from running and the compiler from looking for and loading .net types.
I understand completely that there are .net objects in the OEA environment - and I understand why I got the error.
What am trying to say is that if I happened to instantiate a .net object in my application session, then my existing code is broken.
It is a trivial fix, it is a trivial use case. However, it is still the case that existing code does not work as it did in 10.1.
There may (must) be lots of other developers who use SESSION:FIRST-OBJECT etc to loop through the object chain who may fall into the same trap and report it as a bug / be dissatisfied.
On the other hand, maybe they simply wrote better code than I did
Thanks for the advice though.
However, it is still the case that existing code does
not work as it did in 10.1.
No, the existing code did not have .NET objects, if you add .NET objects you're no longer using the same code, you're using more code. The unchanged application will still run exactly as it did before.
No, the existing code did not have .NET objects, if
you add .NET objects you're no longer using the same
code, you're using more code. The unchanged
application will still run exactly as it did before.
The existing code still does not have .net objects - let's say I add a new program that creates a .net object, and then the existing application is run. The error will happen, even though the code (of the program that encounters the error) has not changed at all. IOW the unchanged program will encounter the error because a new program has created a .net object.
No, the existing code did not have .NET objects,
if
you add .NET objects you're no longer using the
same
code, you're using more code. The unchanged
application will still run exactly as it did
before.
The existing code still does not have .net objects -
let's say I add a new program that creates a .net
object, and then the existing application is run. The
error will happen, even though the code (of the
program that encounters the error) has not changed at
all. IOW the unchanged program will encounter the
error because a new program has created a .net
object.
Yes but if I have an application that references a field without mentioning the table and tomorrow I add a field with the same name to another table the application will also fail. Why? Because the application changed.
Or even better. Imagine you wrote the application exactly as it is now in 10.2, for example because you are not using .NET objects, you will not notice anything. If you suddenly decide to start using .NET objects your application will fail. It's not because of 10.2, it's because of a change in your application. (for me 1 session = 1 application)
Yes but if I have an application that references a
field without mentioning the table and tomorrow I add
a field with the same name to another table the
application will also fail. Why? Because the
application changed.
only because you are not following good practice. (table.field)
Let's put it another way: In 10.1 I can run my application from the OEA. In 10.2 I can't. I have made no code changes to the application at all.
Given the fact, the we should only be weeks from the release of 10.2A, what can PSC do, to make Julian happy again? I guess a change in the product behaviour is unrealistic, so how about a big fat release note entry?
Including the suggestion to use TYPE-OF instead of oRef:GetClass():TypeName .
I'm not sure that I have followed all of this exactly, so can I ask for a clarification, Julian?
In earlier versions, it was common to RUN code in OEA using the same AVM which one was using to parse, syntax check, etc. While keeping down the number of AVMs running, this has some obvious issues, e.g., things which didn't get cleaned up from earlier activities because the session didn't terminate in the way it would had we been doing the RUN in a separate AVM.
So, now we have shifted best practice in OEA such that we are starting a separate AVM for a RUN. No? While this can mean that one ends up with extra hung AVMs needing to be cleaned up, it means that one can have several configurations available for testing at any time. Yes?
Are you saying that, if you follow current best practice and run code which has no .NET references, that you are having the problem? Or is it that you run code which now has .NET references in the session and you are having a problem with code which used to work no longer working because there are .NET entities in the class tree?
If the latter, which is my best guess at the moment, would I be correct that this will be a problem in production, not just in development? That would seem to be true if it were the presence of a .NET class anywhere in the session. Or, are you saying that it only happens in the context of OEA?
If I understood his converns:
IF SomeObject:getClass():TypeName EQ "myapp.library.sessionsingleton" THEN
this issues appears at runtime. As soon as a .NET class is loaded, the SomeObject:getClass():TypeName can fail (when walking the SESSION:FIRST-OBJECT chain) because getClass() does not return a class reference when run for .NET objects.
OK, so the problem is both development and production and as long as one is going to have the potential for .NET objects in the session ... which is rather the point, then the options are to check for a valid object first or use TYPE-OF. Right?
I would think that it should be a fairly straightforward refactoring to change
SomeObject:getClass():TypeName EQ "myapp.library.sessionsingleton"
into
TYPE-OF(SomeObject, myapp.library.sessionsingleton)
Mind you, I can see why Julian is grumbling, but the reasons seem valid, the workaround doesn't seem too difficult, and the new construct is not objectionable in form.
I'm not sure that I have followed all of this
exactly, so can I ask for a clarification, Julian?
Sure thing.
In earlier versions, it was common to RUN code in OEA
using the same AVM which one was using to parse,
syntax check, etc. While keeping down the number of
AVMs running, this has some obvious issues, e.g.,
things which didn't get cleaned up from earlier
activities because the session didn't terminate in
the way it would had we been doing the RUN in a
separate AVM.
True. However, I am still trying to wean myself off pressing the procedure editor button, and typing "run startup.p"
So, now we have shifted best practice in OEA such
that we are starting a separate AVM for a RUN. No?
While this can mean that one ends up with extra hung
AVMs needing to be cleaned up, it means that one can
have several configurations available for testing at
any time. Yes?
Yes. And a very very nice feature it is too. Thanks !
Are you saying that, if you follow current best
practice and run code which has no .NET references,
that you are having the problem?
If there is no .net, everything works just peachy.
>Or is it that you
run code which now has .NET references in the session
and you are having a problem with code which used to
work no longer working because there are .NET
entities in the class tree?
Yes.
If the latter, which is my best guess at the moment,
would I be correct that this will be a problem in
production, not just in development?
Yes.
>That would seem
to be true if it were the presence of a .NET class
anywhere in the session. Or, are you saying that it
only happens in the context of OEA?
No - it's if there is any .net object present in the session, regardless of OEA
If I understood his converns:
IF SomeObject:getClass():TypeName EQ
"myapp.library.sessionsingleton" THEN
this issues appears at runtime. As soon as a .NET
class is loaded, the SomeObject:getClass():TypeName
can fail (when walking the SESSION:FIRST-OBJECT
chain) because getClass() does not return a class
reference when run for .NET objects.
Yes - that's the problem.
OK, so the problem is both development and
production and as long as one is going to have the
potential for .NET objects in the session ... which
is rather the point, then the options are to check
for a valid object first or use TYPE-OF. Right?
Right.
I would think that it should be a fairly
straightforward refactoring to change
SomeObject:getClass():TypeName EQ
"myapp.library.sessionsingleton"
into
TYPE-OF(SomeObject, myapp.library.sessionsingleton)
It was See my earlier posts. I was just grumbling that I had to change my code to move my app into 10.2A. I'm just a bitter old man that wants to run his v3 code unchanged ...
Mind you, I can see why Julian is grumbling, but the
reasons seem valid, the workaround doesn't seem too
difficult, and the new construct is not objectionable
in form.
All absolutely true.
I was just grumbling that I had to change my code to move my app into 10.2A.
Well, if you didn't want to use the new features, you could! No different than those times in the past when one discovered that one had made the mistake of using a field name which turned into a reserved word in a later release. One could always use the keyword forget list to keep going, but then one couldn't use the new feature.
I'm just a bitter old man that wants to run his v3 code unchanged ...
I suspect there's no contest around here who is more of an old man ... but, the really amazing thing about ABL is the extent to which that V3 code still does run. In fact, it is only last week or so that I was educating someone on ProgressTalk about why solving a problem with an editing clause wasn't really the best idea ... he was just copying what he saw everywhere else in his application and was tickled pink to know the answer to someone else's question. When I think what has happened to this language between 1984 when I first discovered it and now, it is staggering and yet how rarely I have had to make a change because of a version shift and when I did it was quite minor.
More likely you are closer to being spoiled than bitter!
Well, if you didn't want to use the new features, you
could!
Yeah, that point was already conceded.
I suspect there's no contest around here who is more
of an old man ... but, the really amazing thing about
ABL is the extent to which that V3 code still does
run.
It's pretty damned amazing. However, I hate to think of the amount of "spaghetti code" that must be lying around supporting all the old v3+ stuff and the poor sod that has to maintain it. It's hard enough for me to maintain my own code from 5 years ago. not some other programmer's from 20 years ago !
More likely you are closer to being spoiled than
bitter
Definitely spoiled.
I hate to think of the amount of "spaghetti code" that must be lying around supporting all the old v3+ stuff and the poor sod that has to maintain it.
Well, as evidenced by that fellow on ProgressTalk, in many cases they don't know any better. They get the job, quite possibly learn the language on the job, look at their own application for examples, and just keep trundling along. Depending on how much they read, they might realize that they are in something of a backwater, but I suspect many of them don't feel the pain the way we would because they really don't know any better. Moreover, even if they do have some perception of being in a backwater, they probably think of it in terms of other languages, not realizing that they are in a terrible backwater with respect to ABL itself.
Of course, the flip side is that it makes a lot of transformation candidates to be my prospect base!
Well, as evidenced by that fellow on ProgressTalk, in
many cases they don't know any better. They get the
job, quite possibly learn the language on the job,
look at their own application for examples, and just
keep trundling along.
Sorry, I meant the "c" code for the ABL itself .
I suspect that the underlying code has had considerably more architectural revision than many of the ABL systems and that it isn't nearly as horrible. This is not to say that there aren't some dinosaurs wandering around in there.
Of course, some of reasons for some of those dinosaurs is exactly the upward compatibility we have enjoyed on the outside. Think how often someone has thought that there were all these places which were doing something similar which could be brought together into common code, but they were quite orthogonal so it was hard to combine and maintain that compatibility. Painful.