Abstract Classes and Methods
I have been looking into using abstract classes and methods. In other languages, if a superclass is defined as abstract, subclasses inheriting from the superclass will not compile until all abstract methods have been implemented in the subclass.
I have created the following classes to try this in Cache:
{
Method testabs(inp As %String) [ Abstract ]{}
}
{
Method testabs(inp1 As %Integer) { w !!,"Input:",$g(inp,"undefined") }
}
When I compile User.Music.AbstractTest it errors because the datatype of parameter inp1 doesn't match the superclass. On changing the parameter to %String it compiles ok (this makes sense to me).
However, if I comment out the implemented method testabs() from AbstractTest it compiles successfully and the object can be instantiated. But according to my understanding, now that testabs() has not been implemented it should either error in compile or when instantiated.
Also, if I add another parameter in addition to the parameters listed, this also seems to be ok.
Have I misunderstood how abstracted classes/methods work? How do others use abstracted classes/methods?
Many thanks.
Hi Ken
In ObjectScript an abstract class simply means that you can not instantiate it. You MUST subclass it and instantiate the subclass.
The concept you understand is supported in Objectscript but it requires that you declare the method itself as abstract.
The two (abstract class keyword and abstract method keyword) work independently of each other.
Does this explain what you are seeing better?
Hi Jenna,
Thanks for your response.
Fully understand your response but unless I am doing something wrong, Cache does not seem to throw an error/warning if the subclass does not implement the abstract methods defined in the superclass.
My understanding is that inherited abstract methods in subclasses must be implemented (even if the implemented method is empty) to standardise class interfaces but in my code this does not seem to be being enforced.
Thanks again,
Ken
You can easily add your own compile-time check via method generators. Here's an example which checks that all abastract methods are implemented.
Class Test.AbstractChecker { ClassMethod Check() As %Status [ CodeMode = objectgenerator, ForceGenerate ] { #Dim sc As %Status = $$$OK // Get class name from %compiledclass object which is an instance of a currently compiled class Set class = %compiledclass.Name // Iterate over class methods. // You can also use %class object to iterate Set method=$$$comMemberNext(class, $$$cCLASSmethod, "") While method'="" { // Get mthod abstract state Set abstract = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHabstract) // Quit iteration when we find any abstract compiled method If abstract { set origin = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHorigin) Set sc = $$$ERROR($$$GeneralError, $$$FormatText("Abstract method %1 in class %2 not implemented (origins from %3)", method, class, origin)) Quit } // Get next method Set method=$$$comMemberNext(class, $$$cCLASSmethod, method) } Quit sc } }
After adding this class to inheritance I get an error on compilation:
Eduard,
Many thanks for the code it does what I am looking for. Do you know if there are plans for the compiler to check for the implementation of abstract methods instead of having to inherit code to do this?
A couple of things I have noticed:
But otherwise that is what I am looking for, I just have to remember to add the AbstractChecker to the inheritance list.
Thanks again.
You can easily modify the method to ignore abstract method if they are system (start with %) or originate from system classes (start with %).
You can modify checker to check whatever you need.
It is, inherited method can accept more arguments than a parent method.
Please file a WRC issue.
Thanks again for the code, it does exactly what I am looking for. However, I have amended the code to list all of the abstract methods required to be implemented for the subclass in the error message.
Class User.Abstract.AbstractChecker { ClassMethod Check() As %Status [ CodeMode = objectgenerator, ForceGenerate ] { k absCheck #Dim sc As %Status = $$$OK // Get class name from %compiledclass object which is an instance of a currently compiled class Set class = %compiledclass.Name ; get the abstract methods set methodCnt=..FindAbstractMethods(class,.methods) ; check whether the abstract methods have been implemented set methodCnt=$order(methods(""),-1) for i=1:1:methodCnt { set method=methods(i) set origin = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHorigin) set errtext=$$$FormatText("%1 [abstract] (origin %2)", method,origin) ; build array of error messages set absCheck("AbsNotImp",$order(absCheck("AbsNotImp",""),-1)+1)=errtext } ; if there are error messages build the error string set str="" if $data(absCheck("AbsNotImp")) { set ind="",ind=$order(absCheck("AbsNotImp",ind)) while ind { set $piece(str,", ",ind)="("_ind_") "_$get(absCheck("AbsNotImp",ind)) set ind=$order(absCheck("AbsNotImp",ind)) } set str="In class '"_class_"' the following "_$order(absCheck("AbsNotImp",""),-1)_" abstract classes are to be implemented: "_str set sc=$$$ERROR($$$GeneralError,str) } quit $get(sc) } ClassMethod FindAbstractMethods(class As %String, ByRef methods As %String) As %Integer { kill methods // Iterate over class methods. // You can also use %class object to iterate Set method=$$$comMemberNext(class, $$$cCLASSmethod, "") While method'="" { // Get method abstract state Set abstract = $$$comMemberKeyGet(class, $$$cCLASSmethod, method, $$$cMETHabstract) if abstract{ set methods($order(methods(""),-1)+1)=method } Set method=$$$comMemberNext(class, $$$cCLASSmethod, method) } quit +$order(methods(""),-1) } }
I'd use $lb instead of local as you don't store anything in subscripts anyway.
HI, Coming from Java, we expect cache to behave same way. However they are two different languages and I learnt that over time.
Both are beautiful languages .