Error when attempting to instantiate an ABC compliant CLASS - Baffled & beaten!

,
Tags: #<Tag:0x00007fc0dae95e60> #<Tag:0x00007fc0dae95d98>

I’ve written a new CLASS - as declared in attached .INC/.CLW files:
jmExtNAME.CLW (1.2 KB) jmExtNAME.INC (725 Bytes)

Why, when I attempt to instantiate this Class, like this …

… do I get this error message: image ??

TiA - John M

Did you remember the INCLUDE(‘jmExtName.inc’)

Note: make certain you have that include line at a global (or module) scope
but it CANNOT be inside of a procedure

 PROGRAM
 MAP
 END
  ! add code to declare SomeFile

 INCLUDE('jmExtName.inc'),ONCE
jmGet  jm::GetExtName
  CODE
  jmGet( SomeFile )

Once you get this working then we can circle back to disuss the class itself.

Many thanks for your quick response, Mark.

Yes, I believe I did. See attached INC/CLW files (above) … Snippet here;

Regards, John M

Look at my example closer
you need the INCLUDE in your PROGRAM
as well as in the jmExtName.clw

@MarkGoldberg If it is setup as an ABC compliant class it automatically gets added to the APP global module.

@JohnM What folder is your class files saved in? It has to be one of the automatically scanned Libsrc folder.
\LibSrc\Win and \Accessory\Libsrc\Win are the two default folders.

Ahh - Doh !
… I was assuming that was being handled by virtue of it being ABC compliant.

Thank you (again), Mark.

Yes, it is, Rick ;
imageimage

That’s what I was assuming too - - Doesn’t seem to be the case, tho (?)

John

I wonder if the INCLUDE is handled via a template

I recall Russ had a template skeleton for abc compliant classes
IIRC this is needed if you wish to have embed points into the class

1 Like

Do you have a “data” dll or is this a single APP solution?
If you have a data dll that exports all the classes and tables from your dictionary, the ABC compliant classes are automatically included.

If I know what you’re talking about :), that is a template to generate a instance of the class into a procedure and include Embed points for each method’s data and code sections. Similar to what an ABC Browse class looks like in a procedure.

I thought that was only with the global DLL, or the EXE without EXTERNAL.

Thanks for all the input, @MarkGoldberg, @Rick_UpperPark and @jslarve … I’m back again (I’m in a different time-zone here; Australia being many hours ahead of the US of A)

Yes, that’s it - - and because it “simply works” I assumed it was part of the magic of an ABC compliant class … but, actually, it’s template-implemented.

To confirm this, I dug into the example of Mike Hanson’s TabPopup template (from a very early version of the SuperStuff template set) … and I found this;
image

… which adds an INCLUDE statement for each PROCEDURE containing a Sheet control

image - Revealed only via Module mode !

ABC compliance is playing a part - - as that must be how the reference to ‘MH::TapPopup’ is able to be translated to a reference to the MHABTABP.INC container for the Class declaration

John M

Yep, all sorted, Mark … and now ready to “circle back”.

Regards, John M

Hi John

just an aside, I think that these days as you can use “ONCE” on your include:

INCLUDE('jmExtName.inc'),ONCE

it is no longer necessary to have the boiler plate omit:

OMIT('_EndOfInclude_',_jmExtName_) ! Omit if already compiled
_jmExtName_ EQUATE(1)

although I guess it doesn’t do much harm… just unnecessary

cheers for now

Geoff R

Thanks, Geoff - I wasn’t aware of that refinement.

Note: There was a small bug in the .INC/CLW files I posted at top of this thread (with big implications; I had the wrong INC file referenced from within the CLW !!). New copies posted here;

jmExtNAME.CLW (1.2 KB) jmExtNAME.INC (1.1 KB)

… with an accompanying template for implementation … jmExtName.TPW (1.7 KB)

John

Some new enhancements;

Filename (1st parameter) can now be OMITTED after first usage … Retained via a STATIC variable.
jmExtNAME.CLW (1.6 KB) jmExtNAME.INC (732 Bytes)

Usage examples included as comments, via the implementation template.
jmExtName.TPW (2.8 KB)

Observations and/or suggestions welcomed …

John

I Agree about using ,ONCE instead of relying the OMIT and EQUATE(1)
especially if you’re using the SV.IDE, IIRC using ONCE results in faster code completion

For other feed back.

  • IMO Ideally the name of the file for the .inc/.clw should match your class name
    that said, ‘:’ isn’t valid in a filename

  • The class name and methods talk about ExternalName
    but the method is returning the result of WHO()

    Do you want to change the result of the method to use
    pFile{PROP:Name, N} where N= WHERE( TheGroup, pField )
    or do you want to rename the class and methods ?

  • Have you considered gettting rid of ExternalName property?
    While it is set, it’s never read, and it’s private
    While it is use as a return value,
    you could instead use a variable inside of each of the methods

  • in your first method .ExtName(FILE pFile)
    the call to SELF.ExtName(pFile, SELF.ExternalName) looks wrong to me
    the 2nd parameter should be a field in a file buffer, not SELF.ExternalName
    note: I haven’t compiled, much less tested any of this

  • the use of ,STATIC on the method variable RecordStructureRef
    allows you to omit the pFile on additional calls
    yes, that will work – but it’s not thread safe
    if you really want to make calls like

    oGetExtName.ExtName( myFile, myFile.ID )
    oGetExtName.ExtName(            , myFile.Description)
    

    then I would move the &GROUP (and/or &FILE) to class properties
    in truth, i’d probably split some logic out.
    yada.Current( MyFile ) ! set SELF.TheGroup &= pFile{PROP:Record}
    and / or
    yada.Current( MyFile.Record ) ! set the SELF.Group &= pGroup

    TheName = yada.GetExtName( MyFile.ID )

Many thanks for your detailed critique, Mark … I appreciate the time/effort you’ve made :+1:

As for any new class, I guess, this has been an iterative process - the latest (renamed) version follows;
jmSQLName.CLW (2.4 KB) jmSQLName.INC (867 Bytes) jmSQLName.TPW (3.3 KB)

Some background;

I’ve always addressed SQL tables via Clarion’s View paradigm - with the “key” to successfully doing so being specification of the SQL server-side labelling of table & column names via the Clarion dct’s External Name attribute = Prop:Name.

All the same, I’ve come across some occasional cases where it’s been necessary to cast some “raw” SQL code (such as for GROUP BY & HAVING statements, specified via the SQL Advanced tab) - - BUT, doing so with server-side syntax within STRING variables means that it’s hidden from the Clarion compiler … and I’d rather have the compiler validate ALL my code, rather than deal with strange bugs after the fact.

So, this class enables me to build compiler-validated SQL statements, using Clarion syntax.

For example, this:


Results in this;

SELECT AppUsage.AppUsageRID,AppUsage.AppUserRID,AppUsage.Date,AppUsage.Time FROM AppUsage WHERE AppUsage.AppUsageRID = 99 ORDER BY AppUsage.AppUserRID


Done - Thanks to Geoff @vitesse for this one; I was naively copying other class definitions.

I use Mike Hanson & Vince Sorensen’s classes & templates as guide/inspiration for my own dabbling; I’m copying their conventions in this case. All the same, I concur with your point on consistency - and I’ve renamed the methods and INC/CLWs accordingly.

WHO returns the field name … that’s what I intend the class to do. The WHERE provides a reference to the specific field. Since I need the WHERE, it just seemed consistent to me to use WHO (instead of PROP:Name) … I “borrowed” the concept from ViewManager.GetFieldName - - ABFILE.CLW

Point taken. Fixed.

Yes, I admit that is a bit of a fudge ! … but I needed (any old) variable to pass as the 2nd parameter - and SELF.ExternalName was handy :wink:

Oops ! - Whilst I had not considered the complications/implications of thread safety, I originally tried declaring the &GROUP reference variable as a class property - but the complier did not like the STATIC attribute in there, which is why I moved it to the method.

Mmm - pondering (I’m writing this in real-time !);

  • Why would thread safety be an issue here ? - - The Class is derived/declared within a Procedure - so, presumably(?), the scope of all its variables is limited to the specific Procedure - and separate from any other Procedures that may have their own instance. What am I not appreciating ?

  • Ahhh !! … The penny drops (with regard to the STATIC issue); I don’t need the STATIC attribute if the &GROUP reference variable is declared at the class level - 'cos it’s then in-scope for all locally instantiated class methods. Oh, der !

  • I’m still not clear/sure about the thread safety issue - Is it OK now (and why was it not before) ? - and, do I need a THREAD attribute on the class (and if so, why) ??


Thanks once again for your help with this, Mark - it’s now a much better design, as a result.

I’ve included all fixes/enhancements in the files attached above.

Regards, John M

1 Like

While Bruce might suggest otherwise, I am firmly of the belief to avoid the SQL Advanced tab, simply create this type of view on the backend, and define the view in the Dct as a table. In addition to having the compiler validate the code, this approach is not Clarion-centric, allows one to later optimize sub-queries on the backend without changing your program, and can permit multi-table updates using an trigger on the view.

GetSQLName.clw (2.6 KB) GetSQLName.inc (1.1 KB)

Please look carefully at the attached files.
Bug found: replace xWho with pWho in the .StripPrefix method