why does IServiceManager:getService not return IService inst

Posted by jankeir on 07-Dec-2017 09:33

I am looking a bit at Ccs and I don't understand why getService does not return IService instead of P.L.Object. In fact, what is the point of IService if not for having a return type for getService? 

Posted by Peter Judge on 07-Dec-2017 09:46

It’s primarily to allow the Service Manager to act as a factory for many types, and not to have the requirement that everything in an application is of type Ccs.Common.IService (since the implementer may not have control over all the code in an application). You’ll also note that the spec has this interface as an optional (not required) interface.

Ideally it should return the type as requested for the service-name.

All Replies

Posted by Mike Fechner on 07-Dec-2017 09:40

IService enforces the initialize() method.
 
So IService is purely to support the factory functionality of the Service Manager.
 
For the consumer the initialize() method has no value anymore.
 

Posted by Peter Judge on 07-Dec-2017 09:46

It’s primarily to allow the Service Manager to act as a factory for many types, and not to have the requirement that everything in an application is of type Ccs.Common.IService (since the implementer may not have control over all the code in an application). You’ll also note that the spec has this interface as an optional (not required) interface.

Ideally it should return the type as requested for the service-name.

Posted by jankeir on 07-Dec-2017 10:02

Aah, I didn't think about services that happen to exist and were not designed with Ccs in mind. That makes sense, thanks for the clarification.

> Ideally it should return the type as requested for the service-name.

That'll require generics I guess?

Posted by Mike Fechner on 07-Dec-2017 11:28

Yes, please! We need generic types and generic methods.
Von: jankeir [mailto:bounce-jankeir@community.progress.com]
Gesendet: Donnerstag, 7. Dezember 2017 17:04
An: TU.OE.Development@community.progress.com
Betreff: RE: [Technical Users - OE Development] why does IServiceManager:getService not return IService instead of P.L.Object
 
Update from Progress Community
 

Aah, I didn't think about services that happen to exist and were not designed with Ccs in mind. That makes sense, thanks for the clarification.

> Ideally it should return the type as requested for the service-name.

That'll require generics I guess?

View online

 

You received this notification because you subscribed to the forum.  To unsubscribe from only this thread, go here.

Flag this post as spam/abuse.

 

Posted by marian.edu on 08-Dec-2017 01:38

I still don’t think the service manager should behave as a factory for ‘everything’ and, although the IService interface doesn’t really add much, the getService method should indeed return a so called ’service’.


As for generics, I don’t see how that could solve the ’should return the type as requested’ requirement… unless we have specialised service manager instances, aka:

ServiceManager<T>:
getService T ()

I do seem to remember there should be only one service manager so, generics will do what exactly?


Marian Edu

Acorn IT 
+40 740 036 212

Posted by Mike Fechner on 08-Dec-2017 01:47

A generic method (as in .NET) would look like

<T> ServiceManager:getService<T> () .

and not

Progress.Lang.Object ServiceManager:getService (T) .

There are good use cases for generic classes (like described by Marian with the ServiceManager<T> and generic methods as described here.

ABL does currently support using .NET Generic types - but not using .NET generic methods in non generic types (unless you go for Reflection: github.com/.../ReflectionHelperOSS )

Posted by marian.edu on 08-Dec-2017 02:30

Argh, not a big fan of the generics methods from .net but that might be just because of my background… I found them just like a more pretentious version of inline casting, generic classes are something else and here I totally agree with you guys that we need those in the 4GL (not just when using .net).

 
Marian Edu

Acorn IT 
+40 740 036 212

Posted by Mike Fechner on 08-Dec-2017 02:33

Get over it, Marian!

It's more than just casting! It's guaranteeing, that the type you request and the type the result is (inline casted to) are the same.

Posted by jankeir on 08-Dec-2017 02:36

Marian, generics would allow this:

define variable interestingService as ISomeInterestingServiceType no-undo.

assign interestingService = Ccs.Common.Application:ServiceManager:getService<>();

Compare that to the current cast stuff and tell me what you like best ;-) There are other use cases where the advantage is bigger (type safety in collection classes comes to mind) as this specific problem can mostly be overcome with a small include but still, it would be a lot cleaner if the syntax were build into the language rather than bolted on.

ps.: Logic in includes: Yuck. 

Posted by marian.edu on 08-Dec-2017 02:46

As said not a big .net fan but I was under the impression the generics methods in .net will require something like this…


define variable interestingService as ISomeInterestingServiceType no-undo.

assign interestingService = Ccs.Common.Application:ServiceManager:getService< ISomeInterestingServiceType >();

If that makes you guys happy then by all means, I can get over it… who knows, I might even start to like it ;)


Marian Edu

Acorn IT 
+40 740 036 212

Posted by Mike Fechner on 08-Dec-2017 02:49

Knowing you well enough, I’m sure you will. It’s still early in the morning and already late in the week. So a little bit of pointless Microsoft bashing is forgiven.

Posted by jankeir on 08-Dec-2017 02:53

Why limit yourself to .NET generics syntax if you have the freedom to design it like it could be. The compiler knows the type of the variable being assigned, so why force repeating it. Less code to maintain and read all the time tends to be better if no confusion is possible.

ps.: The method calling syntax I suggested works fine in Java. Results in very clean code.

Posted by marian.edu on 08-Dec-2017 02:56

Thank you Mike, might be because of the immersion in ‘generics’ I had yesterday… https://en.wikipedia.org/wiki/Mileștii_Mici_(winery) 

I’ll make sure I wear a .Net t-shirt in Dublin :)



Posted by Mike Fechner on 08-Dec-2017 02:56

So you have a better proposal than what's proven to be very helpful in .NET?

Posted by jankeir on 08-Dec-2017 02:57

ps.: Another reason why generics can be better than just casting: docs.microsoft.com/.../constraints-on-type-parameters

You can limit the types that are acceptable to return, so you can make your generic method type-safe at compile time.

Posted by marian.edu on 08-Dec-2017 03:00

That’s a good one Jan, you might have been tasting more wine than I did… but you’re right, let’s make the compiler great again ;)



Marian Edu

Acorn IT 
+40 740 036 212

Posted by jankeir on 08-Dec-2017 03:02

> So you have a better proposal than what's proven to be very helpful in .NET?
Was that a question for me because I said not to limit yourself to .NET syntax? I don't know much .NET but if this is required in .NET-like syntax:

assign interestingService = Ccs.Common.Application:ServiceManager:getService< ISomeInterestingServiceType >().

Than I suggest this:

assign interestingService = Ccs.Common.Application:ServiceManager:getService<>().

(like it's done in Java by the way)  

Posted by Mike Fechner on 08-Dec-2017 03:05

So the <T> parameter is determined by variable it's assigned to? Don't think I like that (and Marian, I was not near a winery yesterday). In case of subtyping I can see cases where being explicit on the type you request is important.

Posted by Mike Fechner on 08-Dec-2017 03:10

Jan, where do you see a reference to a Java generic method with no parameters?

docs.oracle.com/.../methods.html

So me it is seems that Java is determing the type parameters from the actual method arguments. But that would always require an argument....

Posted by jankeir on 08-Dec-2017 03:24

Hmm, I may have it confused with the constructor syntax ( SomeClass<Integer, String> sometobject = new SomeClass<>(); does work, no time to check the method right now, but there is no reason why it couldn't work.)

I feel like listing the type again if it is already known from the variable that's being assigned is like suggesting this for a for each on a buffer:

for each bufCustomer <customer> where bufCustomer.custno <customer.custno> = 123 :

 ...

end.  

Since the buffer is defined on the customer table there's now reason to list it over and over again, why would we insist on doing exactly that when we are referring to variable types? You should allow it (for when you are not storing the result of a method but directly calling a method on the result for example) but I see no reason to enforce it if the compiler can figure it out. Again, as long as it is clear and no confusion is possible, why add overhead to code. If it doesn't add anything I don't think it should be there.

Posted by Mike Fechner on 08-Dec-2017 03:27

Buffers have not super and sub types. IMHO a significant difference for your case.

Posted by marian.edu on 08-Dec-2017 03:34

The only problem there Jan is how do you know, from generic method, what you should return to the caller? Mike is right, in Java generic methods only work with type parameters so inside the method you know what need to be returned from the type of input parameter(s).



Marian Edu

Acorn IT 
+40 740 036 212

Posted by bronco on 08-Dec-2017 03:43

getService<T>('myService') is pointless since we already have casting. (although imho the CAST function looks ugly).

assign interestingService = Ccs.Common.Application:ServiceManager:getService<>(). is no good as well, since that

throws away the concept of Strong Typing (if getService returns a P.L.O. you want the compiler to tell you that you're mixing up the types, that's the whole point of Strong Typing).

The other way around would be nice and is called Type Inference. This would mean something like:

def var myService = serviceManager:GetService('logservice').

Now if the GetService method returns an IService type, the myService var would be automatically of the type IService.

Posted by jankeir on 08-Dec-2017 03:51

Something like this should work:

method public <T> getService ( ):

find first ttservice where get-class(ttservice.service).isA(T) no-error.

if avail ttservice then return cast( ttservice.service , T).

else undo, throw....

end.

What's the point of the generics if you still need to cast? The point is that you only need it once in a single place where you can add rigorous type checks and testing instead of polluting all your code on every call.

Mike, as said, you should be able to modify the type, ie in the call for cases of inheritance and such, but assuming that inheritance is not overused, I expect that to be needed only in the exception rather than the general case.

Posted by bronco on 08-Dec-2017 04:25

Generics are meant for run compile time type checking, what you're showing is still runtime behaviour. The undo, throw is the same what you would get is the cast doesn't work out because incompatible types. Generics are handy when you use it to make sure what you put into a class is of Type T. For example:

def var list as ArrayList<IService> no-undo.

list = new ArrayList<IService>().

list:Add(bla).  // fails on compile time if you put anything else than an IService in it.

And then it would be handy to have an:

def var myService as IService no-undo.

myService = list:get('service_abc').  // because get returns T

But only because you know (because of generics) that there are only T's in the collection.

Posted by marian.edu on 08-Dec-2017 04:26

That will work if you define the class to be generic, aka ServiceManager<T>… or ServiceManager<T extends IService> to be more precise :)


When using generics methods then you need to pass somehow the type to the method, generics method in a non generics class is only possible in Java if there are some input parameter to infer the type from.

If implemented the .net way it will be something like this:

define it like 
method public <T> getService ( )

and make the call
ICustomService  myService = getService<ICustomService>().

The Java equivalent might look like this…

method public <T> getService (P.L.Class<T> cls)

and call it with
ICustomService  myService = getService(ICustomService.class).

Only in 4GL is not easy to get the class ‘instance’ and somehow this doesn’t look appealing to me :(

ICustomService  myService = getService(P.L.Class:getClass(‘ICustomService’)).

Marian Edu

Acorn IT 
+40 740 036 212

Posted by jankeir on 08-Dec-2017 05:58

All I am saying is that a syntax like this:

assign interestingService = Ccs.Common.Application:ServiceManager:getService<>().

and

Ccs.Common.Application:ServiceManager:getService<ISomeInterestingService>():doSomething().

calling a method like this:

method public <T> getService ( ):

...

end.

could be made to work in ABL and would result in very clean code in the users of the calling service.  

This thread is closed