[Grace-core] initialisation & checking

James Noble kjx at ecs.vuw.ac.nz
Mon Apr 29 23:59:36 PDT 2013


Brief replies:

> First, do I remember correctly that we are not meeting this week (Monday or Tuesday)?

let's try & meet. I can't do mon US next week either,  taking on Grace at UBC...
will check about tuesday US

> I must admit, I don't see that this is a huge problem.  Other languages do it.  Sometimes the rules are more complicated, but it is doable.

indeed

> I would hate to see us ban executable code that might use "self" in intiitialization.  

me too

> The REPL case makes it clear we want to be able to execute code before the object is complete, including calling newly defined methods (which are, after all, self calls). 

indeed. I'm happy with making the REPL a special case, I think it just has to be.
you want to be able to redefine methods in the REPL for example,
and you can't do that anywhere else! 
> 
> Let me make up some new terminology to help describe initialization.  Let's take the statement that we "prepare" an object to mean that slots are allocated for all definitions and variable declarations of an object and method definitions are loaded into slots for methods.  However, this does not include elaborating definitions or initializing variables.  Thus after "preparation", an object has been structurally formed so code accessing definitions, variable declarations, and method invocations  can be set up properly (even if that code would crash if actually run at this point).

yes and yes.

> How do we prepare an object with an "inherits" clause?  While I don't believe we have specified this before, it is certainly easy to require the "inherits" clause to be the first thing that appears in a class definition (if it occurs at all) -- before new definitions, variable declarations, or methods.  Then to prepare an object being formed using an inherits clause, we would go through the process of preparing the object/class being inherited from, while also inserting the slots for the new definitions and variable declarations, and doing the insertion of new methods and overriding old ones.

yep.

>  In particular, if a method is inherited and overridden, only the new overriding method body is available.  (I'm ignoring "super" calls fin this e-mail.)  Note that at this point, no definitions have been elaborated or variables initialized, whether from the inherited or new object..  We could then go through and run the initialization code of the superclass/object (i.e., elaborate definitions and initialize variables) where "self" is interpreted as the new object, followed by running the initialization code of the new object being defined.  

yep.

> [While I haven't indicated it here, I think one could pretty easily specify the order of the initialization code for each object -- basically from top to bottom.  Methods have the advantage that nothing is executed when they are defined and installed -- they are closures, after all, so the order of installing them makes little difference as long as the overriding methods replace those being inherited.]

this is what we say: init code runs top-to-bottom.  
But methods aren't "really" quite closures (or at least not really quite blocks...)
I guess Andrew would say they are pre-closures?

> Of course, when running the initialization code for the superclass, a method overridden by the subclass may be invoked and that may access a definition or variable that has not yet been initialized.  That is a programmer error and would cause a run-time error.  We could work hard to make those impossible to write with legal code, but I personally think that is overkill.  I believe students need to understand something about the order of initialization.

me too.  Again, we can have pluggable checkers to prevent these errors,
just as we have checkers to prevent type errors.

> I suspect there are some corner cases I haven't considered above, and we can argue about whether we want initialization in variable declarations to be treated differently from initialization in assignment statements that are not part of declarations (though, having just talked about this in C++, I would prefer not to get into similarly horrible distinctions in Grace).

indeed - but I don't think we need to! 

> So, I'm sure you'll let me know where I've ignored important cases, but in the worst case we can simply look back and do what Java or Scala do.  It works, and seems not to confuse programmers.  Is there anything we are doing that would make it worse than in those cases?

I think we're already better. and we have discussed a range of workable options

James

> Kim
> 
> 
> 
> On Apr 27, 2013, at 10:26 PM, James Noble <kjx at ecs.vuw.ac.nz> wrote:
> 
>>> Yes, I agree that this is a serious problem.  The root cause is that we have been using "top level code" in object constructors to do two things.
>>> 
>>> (1) In the REPL, and in Modules, it's just code that should  be executed asap.  In the REPL in particular, we want it executed before the object is completely created, which ca't happen until the END of the object constructor is reached.
>> 
>> in some cases at least, this is the case for code in objects generally.
>> Certainly for debugging, its great to just dump some code in there to print or something.
>> 
>>> (2) In inherited objects, we want to delay the execution of the top level code until after all of the sub-objects have been created, since the sub-objects might change the meaning of any of that code.
>> 
>> right. I now think this *is* a special case, we don't support it, and we probably should.
>> But it's really only required for framework builders, not even simple inheritance
>> for modelling (I think).
>> 
>>> There desires are fundamentally in conflict.   We can eliminate that conflict by banning the offending code.  Other proposals are welcome!
>> 
>> banning the offending code isn't enough.
>> Some way of doing the right thing would be nice!
>> 
>>> If we do ban executable code in object constructors, then we would need to make modules and "scripts" something else.    The obvious choice is methods, but I have to admit that I really dislike the idea of a "main method" as in Java — the name "main" makes it sounds as though that method should be important, whereas in fact it's unimportant.
>> 
>> right. so let's not do that...
>> 
>>> Michael is also right that our model for doing procedures-first required the incremental growth of objects by adding methods, which could be requested as soon as they were added, even though the object is incomplete.  It does seem a shame to loose that — but I am more concerned with having a sensible semantics for objects than being able to use methods like procedures.
>> 
>> whether the REPL is a module or a method or whatever, it's going to be special:
>> it has to run when it is in some sense "incomplete".
>> But I think it always makes sense to build the "structure" of the whole object,
>> including method, before doing initialisation so I don't see this as a problem. 
>> Forbidding inline code is a problem. 
>> 
>> Again - surprisingly perhaps - I'd like clear, straightforward explicable semantics,
>> first of all - something to tell the children as Andrew puts it.  If we want to rule 
>> out programs, we can do that with a dialect. I don't see that a dynamic variable not
>> initialised error as worse than a dynamic no such request error - a type system could
>> rule that out, but that shouldn't be part of the fabric of the language.
>> 
>> James
>> 
>> 
>> _______________________________________________
>> Grace-core mailing list
>> Grace-core at cecs.pdx.edu
>> https://mailhost.cecs.pdx.edu/mailman/listinfo/grace-core
> 
> 



More information about the Grace-core mailing list