*do you know if the OCUndeclaredVariable is raised for unknown superclass?*
this code:
AnUnknownClass subclass: #Adaptor1Example
instanceVariableNames: 'customers accountID address name
phoneNumber'
classVariableNames: ''
poolDictionaries: ''
category: 'Examples-Cookbook'
is run as a Do It. In Do It, unknown variables (as here AnUnknownClass)
raise an OCUndeclaredVariableWarning.
For example, running:
AnUnknownClass subclass: #Adaptor1Example
instanceVariableNames: 'customers accountID address name
phoneNumber'
classVariableNames: ''
poolDictionaries: ''
category: 'Examples-Cookbook'
executes the default action for OCUndeclaredVariableWarning, which is
opening a pop-up titled: "Unknown variable ...". Here the error is raised
at *compilation time, *therefore it would have* no effect to wrap this with
a #on:do: *
[ AnUnknownClass subclass: #Adaptor1Example
instanceVariableNames: 'customers accountID address name
phoneNumber'
classVariableNames: ''
poolDictionaries: ''
category: 'Examples-Cookbook' ] on: OCSemanticWarning do: [ ]
==> same problem.
Now if you do:
[ OpalCompiler new evaluate: 'AnUnknownClass subclass: #Adaptor1Example
instanceVariableNames: ''customers accountID address name
phoneNumber''
classVariableNames: ''''
poolDictionaries: ''''
category: ''Examples-Cookbook''' ] on: OCSemanticWarning do: [ :e |
e halt ]
Here we catch the error, and you can handle it.
Now it is not easily possible to resume the error, because you want a
global instead and Opal expects a temp (there are way to resume but with
very deep stack manipulation that I do not want to show to young pharoers
present on this mailing list). So the best is to retry it. One solution is
therefore:
[ OpalCompiler new evaluate: 'AnUnknownClass subclass: #Adaptor1Example
instanceVariableNames: ''customers accountID address phoneNumber''
classVariableNames: ''''
poolDictionaries: ''''
category: ''Examples-Cookbook''' ]
on: OCSemanticWarning do: [ :e |
Smalltalk at: e node name put: StubRootClass.
e retry ]
with e node name answering #AnUnknownClass here.
Now you need to make sure that the exception block is executed for the case
of a missing superclass and not something else or you will end up creating
loads of globals.
The exception block should be something similar to:
[ :e |
e node name first isUppercase and: [ "some condition" ] ifTrue: [
Smalltalk at: e node name put: StubRootClass.
^ e retry ].
e pass ]
*How to undefined and OCUndeclaredVariableWarning relate?*
In your case, while loading from Monticello the code is compiled and
evaluated in non interactive mode. Therefore it cannot trigger the default
action of OCUndeclaredVariableWarning which is a UI event. So it sets by
default the unknown global to:
Undeclared at: varName asSymbol put: nil.
OCUndeclaredVariable new name: varName asSymbol
in: OCUndeclaredVariableWarning >>defaultAction
which then later triggers the code in UndefinedObject.
2013/12/3 Stéphane Ducasse <[email protected]>
>
> On Dec 3, 2013, at 11:20 AM, Clément Bera <[email protected]> wrote:
>
> Then for your project replace ProtoObject by StubRootClass in
> UndefinedObject>>subclass:instanceVariableNames:classVariableNames:
> poolDictionaries:category: it will work.
>
>
> yes but this is ugly because I do not want override.
> So I will introduce an exception so that we can do that in a clean way.
>
>
> An alternative is to catch OCSemanticWarning or its subclass
> OCUndeclaredVariableWarning while loading the new classes and execute
> another code instead of the default action in the exception handling block
>
>
>
> do you know if the OCUndeclaredVariable is raised for unknown superclass?
> How to undefined and OCUndeclaredVariableWarning relate?
>
> Stef
>
>
>
> 2013/12/3 Stéphane Ducasse <[email protected]>
>
>> > Well if the class does not exists it calls the method on
>> UndefinedObject (UndeclaredBinding). And you have:
>>
>> I will check and see if I can set up a hook because having classes
>> subclasses of protoobject is not a good idea
>> when loading broken code.
>>
>> > UndefinedObject>>subclass: nameOfClass
>> > instanceVariableNames: instVarNames
>> > classVariableNames: classVarNames
>> > poolDictionaries: poolDictnames
>> > category: category
>> > "Calling this method is now considered an accident. If you
>> really want to create a class with a nil superclass, then create the class
>> and then set the superclass using #superclass:"
>> > self traceCr: ('Attempt to create ', nameOfClass, ' as a subclass
>> of nil. Possibly a class is being loaded before its superclass.').
>> > ^ProtoObject
>> > subclass: nameOfClass
>> > instanceVariableNames: instVarNames
>> > classVariableNames: classVarNames
>> > poolDictionaries: poolDictnames
>> > category: category
>> >
>> > The best is to set manually the superclass after with #superclass:
>>
>> No because I have no idea what are the classes whose superclasses are not
>> in the image.
>> With a proper hook I could just say
>> if the superclass is unknow please use the "StubRootClass" of my
>> framework.
>> else let the system handles it.
>>
>> Stef
>>
>
>
>