Project

General

Profile

Feature #9868

Support generics introduced in Progress 12.x

Added by Ioana-Cristina Prioteasa over 1 year ago. Updated 9 days ago.

Status:
WIP
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

0%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

MultipleImplements.cls (1.09 KB) Ioana-Cristina Prioteasa, 04/02/2025 07:36 AM

TestMultipleImplements.cls (2.53 KB) Ioana-Cristina Prioteasa, 04/02/2025 07:36 AM


Related issues

Related to Base Language - Feature #9488: implement all built-in OO classes using the open source ADE code from 12.8.4 WIP

History

#1 Updated by Ioana-Cristina Prioteasa over 1 year ago

  • Related to Feature #9488: implement all built-in OO classes using the open source ADE code from 12.8.4 added

#2 Updated by Ioana-Cristina Prioteasa over 1 year ago

Progress 12.x introduced built-in classes that use generics, such as Progress.Collections.HashMap and Progress.Collections.List.

Use cases include:
  • Declaring variables with generics:
    • def private serializable var mBackingList as Progress.Collections.IList<Object>.
    • var private HashMap<ILongcharHolder, Object> mBackingHashMap.
  • Instantiating generic objects:
    • this-object(new Progress.Collections.List<Object>()).
    • constructor private List (input pBackingList as Progress.Collections.IList<Object>):
  • Navigating generic structures:
    • var Progress.Collections.IIterator<KeyValuePair<ILongcharHolder, Object>> iter.
      assign hValue = iter:Current:Value.
      

      Here, Value is a property from KeyValuePair.

Additional considerations:

  • A class can implement the same interface multiple times with different type parameters:
    CLASS MultipleImplements
    IMPLEMENTS IComparable<OpenEdge.Core.Integer>,
               IComparable<OpenEdge.Core.Decimal>:
    

    Here the class needs to contain 2 compareTo methods:
    • METHOD PUBLIC INTEGER CompareTo(other AS OpenEdge.Core.Integer):
    • METHOD PUBLIC INTEGER CompareTo(other AS OpenEdge.Core.Decimal):
      I attached the completed MultipleImplements.cls and TestMultipleImplements.cls - an unit test on this matter.
  • Instantiating a generic class without type parameters is invalid syntax in Progress 12. This is not permitted:
       myList = NEW List().
    

#3 Updated by Greg Shah over 1 year ago

For convenience, I'm reproducing my post from #9488-131:

Greg: considering that the #9457 project doesn't use generics in the app code, I want to find a way to delay this implementation. One of the 'weird' parts is:
[...]

Note how you can implement the same interface but with different generic types. This is not allowed in Java.

Yuck. Some things to record for posterity:

  • OO 4GL currently (as of the latest 12.8 LTS) doesn't have generics support that can be used by end user code. These references are only in the built-ins. Presumeably, they implement this limited special support in the native code of the OE runtime.
  • OE is shrinking (dying actually) annually and the next LTS release is not expected until at least 2027 (best case) as explained by Progress Software Corp's (PSC) themselves. Most (all?) commercial ISVs would never deploy an OE release that is not LTS. That means that no one will be deploying the post-12.8 LTS until 2027 or possibly long after that.
  • Supposedly PSC is working on generics for OO 4GL but generics can't appear in real OO 4GL code that goes to customers until that next LTS release is available so we have years to go before end user code will ever have direct access to generics.
  • I wonder if OE will still exist in 2028 or if it will just be in maintenance mode. Actually, it is already kind of in maintenance mode since the amount of development on OE itself is very limited. But for the sake of argument, let's say that maintenance mode is in the future somewhere. My suggestion is that given the pace of decline, maintenance mode is possibly not that far in the future. Under those conditions we may never have to implement generics in the FWD implementation of the OO 4GL.
  • Nevertheless, the current approach chosen by PSC seems to match the C# concept of generics which uses runtime information and tends to be much slower than generics in Java which use type erasure and are fast but have more type limitations on the implementation. As you note, we can't directly implement two parameterized interfaces using Java generics because of the type erasure implementation.

If it is feasible to defer the work on generics to another task, I am OK with that so long as that work can be deferred to after the current projects are complete. My point here is that if we defer the work but then just have to work it again in order to finish some current projects, then the deferral doesn't help too much. So, I'd like to know if we need it in the short term or not. If not, then we should defer it.

#4 Updated by Greg Shah over 1 year ago

I'm guessing that there is no syntax in the built-in classes which shows how to define a parameterized type (e.g. T like in a Java definition public class MyGenericisedClazz<T> { /* references to type T */ }). Is that correct?

In other words, they have some sytnax to reference existing classes that implement generics but not to define them in a class.

#5 Updated by Greg Shah about 1 month ago

We need to evaluate the OE v13 user-defined generics support. Hopefully it is compatible. We should just implment support for that and the OO built-in usage will "come along for the ride".

#6 Updated by Octavian Adrian Gavril 12 days ago

  • Status changed from New to WIP
  • Assignee set to Octavian Adrian Gavril

#7 Updated by Octavian Adrian Gavril 11 days ago

Evaluated the v13 user-defined generics support. It looks compatible and I think one implementation covers both cases.

Progress says as much in the 13.0 release notes: user-defined generics extend the same generic programming model the built-in collections already use, it's not a separate mechanism. That also answers what you asked in note #9868-4: 13.0 does have syntax to define a parameterized type, for classes and interfaces both:

CLASS class-name <type-param AS type-constraint [, type-param AS type-constraint]...>

The reason the built-in usage comes along for the ride is that in FWD the built-ins aren't special. They're the fakeout .cls skeletons under skeleton/oo4gl/, parsed by the same parser as any application class. Right now those skeletons are non-generic, everything flattened to Progress.Lang.Object. We stripped the generics by hand when the skeletons were generated, since the parser can't accept <> in a 4GL type name. Once it can, we rewrite them with the real signatures and the built-ins are generic for free. However, with all the work done in #9638, we will only need the implementations and we won't need the skeletons anymore.

Roughly the work is:

  • accept <...> in the grammar, both in type references and in class/interface declarations;
  • carry type parameters and arguments through ClassDefinition / MemberData / MethodData and substitute them on member lookup;
  • add GetTypeParameters() and GetTypeArguments() to LegacyClass. We only have isGeneric() today, and GetTypeArguments() isn't optional, it's the documented way around the NEW T() restriction;
  • finish the built-ins themselves: HashMap, KeyValuePair and IIterator are still non-generic and IMap is single-parameter.

The one real extra problem is the case you raised in #9488-131, implementing the same interface with different type arguments. I don't think it's a blocker. Java overloads on the signature, so two methods with the same name and different parameter types are fine as they are, and where the signatures would actually collide we already apply suffixes (that's what produces write_1 / write_2 in converted output). Either way the two CompareTo methods are covered. For the implements clause I think we should emit the interface once, unparameterized, and generate a bridge method that dispatches on the runtime argument type to the suffixed ones. We can't simply drop the implements, since LegacyClass relies on Class.isAssignableFrom for TYPE-OF and CAST.

#8 Updated by Greg Shah 11 days ago

It isn't clear to me how the converted code will change to support type parameters. Are you saying that we should not support it directly in Java syntax but instead handle the overloading purely via name suffixes?

This is OK for cases that don't map directly to Java but for those cases that could be supported by Java generics, we would want to leverage those if possible because the converted code outcome is much better.

Please focus on writing a complete test suite (added to Testcases), the various cases can be written as OO classes and then ABLUnit tests to use those classes and prove conformance.

#9 Updated by Octavian Adrian Gavril 9 days ago

Greg Shah wrote:

Please focus on writing a complete test suite (added to Testcases), the various cases can be written as OO classes and then ABLUnit tests to use those classes and prove conformance.

I successfully set up an OE environment using v12.8, as the OE Developer Kit for v13.0 isn't available yet.

Also available in: Atom PDF