ECMA status on self-initialization

6 messages Options
Embed this post
Permalink
helmut.brandl

ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
There has been some discussion on how self-initialization shall be
handled and there are different positions.

The following tries to summarize what the current position of the ECMA
committee seems to be:

1. All expanded types must have default_create available for creation

2. All expanded types are self initializing in the sense that the
compiler calls default_create for all local variables and attributes.

3. An attribute block for expanded types is invalid.

4. Reference types can make default_create available for creation or not
(this is a decision of the designer).

5. Reference types are never self initializing in the sense that the
compiler will allocate the object and call default_create. This is to
avoid surprise semantics.

6. Attribute blocks are allowed only for attached reference types which
don't make default_create available for creation. Attribute block for
detachable types are invalid.

7. The types ARRAY[SOME_ATTACHED_REFERENCE_TYPE] and
SPECIAL[SOME_ATTACHED_REFERENCE_TYPE] cannot be void safe in the current
definition, because neither the class ARRAY nor SPECIAL are able to
initialize the elements. Therefore a value to initialize them has to be
provided to each creation procedure.

This is the picture I can draw from the remarks I have heard in the last
months.

In my opinion there are some inconsistencies in these rules. Furthermore
I don't like the asymmetry between expanded and reference types and
think that especially rule #1 will make non trivial expanded types very
clumsy.


Kind regards
Helmut
dlebansais

Re: ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
In my opinion, #7 is a much bigger issue than #1. However, I don't work with expanded types much, only with the basic ones. You probably have problems with them that I never meet.

#7 on the other hand affects most Eiffel programmers since ARRAY is a pretty common construct in programs.

But let's address #1.

> 1. All expanded types must have default_create available for creation

> I don't like the asymmetry between expanded and reference types and
> think that especially rule #1 will make non trivial expanded types very
> clumsy.

The ability for a compiler to build the initialized value of an expanded type is in my opinion critical for basic types (INTEGER and such). I've been working with uninitialized integers in C++ for years and hated it every single time.

In the declaration

i: INTEGER

the ability for i to acquire a default value before any code having access to it is executed is in my opinion critical. If we don't agree on this, I don't think our opinions can be reconciled. ;)

Starting from this, it seems straightforward logic to extend the mechanism to all expanded types and attached reference, for the sake of never leaving anything uninitialized. Detachable reference types are just another form of expanded data, with initialized value 'void'.

When you speak of "non-trivial expanded types" I assume you're talking about classes containing references, leading to some complexity if there are recursive references for instance.

The problem is that if the programmer can't expect an expanded type to be initialized with a definite, fixed value, it might as well be uninitialized.

In the declaration

an_expanded_variable: AN_EXPANDED_CLASS

what additional syntax do you suggest that would let an_expanded_variable take different value based of some parameter? There is no need for one, you already have it with the call

an_expanded_variable.make(<insert parameters here>)

The only requirement being that the class invariant stands at the time of the call, i.e. the class has a default creation mechanism.

I can see two ways out of this situation:
. Allow explicitely uninitialized expanded types. For instance with a new 'uninitialized' keyword (or some other notation as name clashes is another of our concerns)
These types would allow deferred initialization to occur at the first call, permitted only to a creation procedure, and would not check the class invariant until the creation procedure ends.

. Require default_create for all expanded and attached reference types, at the expense of clean design. Forcing programmers to use default values that don't make much sense, or to lessen class invariant requirements to allow for these unnatural values that are there only for initialization sake.

I can see why default_create seems a better choice to keep the language simple, since you need it anyway. Also, there might be some concern at the implementation level when handling uninitialized variables. Every call would have to check if the object is initialized.

I think that in your code you pay the price for copy semantic by having to use clumsy design. Isn't it just a tradeoff?

David Le Bansais


helmut.brandl

Re: Re: ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
Hello David,

the answers to your questions see below.

Regards
Helmut

dlebansais wrote:
> In my opinion, #7 is a much bigger issue than #1. However, I don't
> work with expanded types much, only with the basic ones. You probably
> have problems with them that I never meet.
>
> #7 on the other hand affects most Eiffel programmers since ARRAY is a
> pretty common construct in programs.

Agreed. Many developers are not affected by #1, because they don't use
expanded types. But nearly all need ARRAYs. Therefore the priority it clear.

>
> But let's address #1.
>
>> 1. All expanded types must have default_create available for
>> creation
>
>> I don't like the asymmetry between expanded and reference types and
>>  think that especially rule #1 will make non trivial expanded types
>> very clumsy.
>
> The ability for a compiler to build the initialized value of an
> expanded type is in my opinion critical for basic types (INTEGER and
> such). I've been working with uninitialized integers in C++ for years
> and hated it every single time.
>
> In the declaration
>
> i: INTEGER
>
> the ability for i to acquire a default value before any code having
> access to it is executed is in my opinion critical. If we don't agree
> on this, I don't think our opinions can be reconciled. ;)

There is no disagreement on this. All variables (local variables and
attributes have to be initialized before its use. That is critical to
high quality software. Regardless whether they represent expanded or
reference type objects.

>
> Starting from this, it seems straightforward logic to extend the
> mechanism to all expanded types and attached reference, for the sake
> of never leaving anything uninitialized. Detachable reference types
> are just another form of expanded data, with initialized value
> 'void'.

ok.

>
> When you speak of "non-trivial expanded types" I assume you're
> talking about classes containing references, leading to some
> complexity if there are recursive references for instance.

Exactly. I mean expanded type objects which do not have a reasonable
default value. Everybody agrees that many reference types don't have a
reasonable default value. But many expanded types don't have a
reasonable default value either. Just the `trivial' ones, i.e numbers
like INTEGERs and REALs or BOOLEANs.


>
> The problem is that if the programmer can't expect an expanded type
> to be initialized with a definite, fixed value, it might as well be
> uninitialized.

This shall be avoided. A consequence of lack of initialization is in
many cases a violated invariant.

>
> In the declaration
>
> an_expanded_variable: AN_EXPANDED_CLASS
>
> what additional syntax do you suggest that would let
> an_expanded_variable take different value based of some parameter?
> There is no need for one, you already have it with the call
>
> an_expanded_variable.make(<insert parameters here>)

The mechanism I have in mind is quite simple. If the object has a
reasonable default value, the designer of the class can provide the
argumentless `default_create' for creation. With that the compiler can
initialize all attributes and local variables before they can be accessed.

If there is no reasonable default value, the user have to create (i.e.
initialize) it explicitly with the Eiffel construct

   create an_expanded_variable.make(arg1,arg2,...)

If the `create' is missing the compiler shall raise a validation error
at compile time. With that rule it can be guaranteed that at runtime you
never access an uninitialized variable or attribute.


>
> The only requirement being that the class invariant stands at the
> time of the call, i.e. the class has a default creation mechanism.
>
> I can see two ways out of this situation: . Allow explicitely
> uninitialized expanded types. For instance with a new 'uninitialized'
> keyword (or some other notation as name clashes is another of our
> concerns) These types would allow deferred initialization to occur at
> the first call, permitted only to a creation procedure, and would not
> check the class invariant until the creation procedure ends.

I don't understand what you mean by that. I don't want uninitialized
expanded type objects. Expanded type objects have to be initialized
either explicitly (by a creation call) or implicitly (by letting the
compiler make the creation call with `default_create').

>
> . Require default_create for all expanded and attached reference
> types, at the expense of clean design. Forcing programmers to use
> default values that don't make much sense, or to lessen class
> invariant requirements to allow for these unnatural values that are
> there only for initialization sake.

That is exactly my concern with the current ECMA status on expanded types.

>
> I can see why default_create seems a better choice to keep the
> language simple, since you need it anyway. Also, there might be some
> concern at the implementation level when handling uninitialized
> variables. Every call would have to check if the object is
> initialized.

This is not necessary. It can safely be checked at compile time.
Therefore there is no degradation of performance.

>
> I think that in your code you pay the price for copy semantic by
> having to use clumsy design. Isn't it just a tradeoff?

If the current ECMA status does not change, non-trivial expanded types
won't be used. That is the consequence.


>
> David Le Bansais
>
>
>
>
> ------------------------------------
>
> Yahoo! Groups Links
>
>
>
dlebansais

Re: ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
Hi Helmut

So, in summary you would like expanded types to be initialized at the time of first use?

It makes sense to me. I'm a bit worried about what 'time of first use' can be, when you can have exceptions, invariants, and pre/post conditions and maybe other stuff happen before your code, or not.

What in your opinion is the reason the 'default_create' approach is preferred?


helmut.brandl

Re: Re: ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
dlebansais wrote:

> Hi Helmut
>
> So, in summary you would like expanded types to be initialized at the
> time of first use?
>
> It makes sense to me. I'm a bit worried about what 'time of first
> use' can be, when you can have exceptions, invariants, and pre/post
> conditions and maybe other stuff happen before your code, or not.
>
> What in your opinion is the reason the 'default_create' approach is
> preferred?

Let us make an example and assume that the type SELF_INIT_EXP is a self
initializing expanded type (i.e. `default_create' is available for
creation).

Then you can write

  local
    s: SELF_INIT_EXP
  do
    ...
    s.first_feature_call_on_s
    ...
  end

and this is what the compiler makes from that

  local
    s: SELF_INIT_EXP
  do
    create s.default_create  -- implicit statement
                             -- generated by the compiler
                             -- for your convenience
    ...
    s.first_feature_call_on_s
    ...
  end

So the compiler makes the initialization for you. You don't have to
worry. There is nothing wrong with that, it is common practice in Eiffel
for many years now and there is no disagreement about that (sidenote:
the compiler can place the initialization statement anywhere before the
first feature call on the object, but most probably will do it at the
start of the body).

The only thing I am worried is that there are expanded types which have
no reasonable default value, i.e. they cannot make `default_create'
available for creation. The publicly available ECMA standard allows that
but the ECMA committee announced that they will disallow that.

But let us assume for a moment that it is possible to define a type
NO_DEF_EXP which does not make `default_create' available for creation.
Then the following is invalid code

  local
     e: NO_DEF_EXP
  do
     e.first_feature_call_on_e -- error: use of uninitialized `e'
     ...
  end

and the compiler has to flag a validation error on that code. You can
make this code valid by

  local
     e: NO_DEF_EXP
  do
     create e.make(arg1,arg2,...)
     ...
     e.first_feature_call_on_e
     ...
  end

All I am saying is that I would like to have that second possibility.
Note that in both ways the compiler generates only code with all
variables properly initialized, either implicitly or explicitly initialized.


In your last sentence you asked what might be the reason to forbid this
second possibility. I don't know. But I assume it is because of the
still unresolved initialization problem of array elements.

If the compiler enforces that all expanded types have `default_create'
available for creation it can initialize all elements of an array by its
default value. With this rule you could guarantee that
ARRAY[SELF_INIT_EXP] will only have initialized items.

Sounds nice?

But there is a however: What happens with
ARRAY[SOME_ATTACHED_REFERENCE_TYPE]?

For reference types you don't have this rule that all reference types
have to make `default_create' available for creation. How shall the
compiler initialize the entries of such an array? Void is not a legal
value, because the elements are attached. The compiler cannot call any
of the creation procedures because it does not know which one and if he
picked one it cannot provide the arguments.

Conclusion: Requiring `default_create' for all expanded types does not
solve the initialization problem for array elements completely.


Regards
Helmut
dlebansais

Re: ECMA status on self-initialization

Reply Threaded More More options
Print post
Permalink
Hi Helmut.

That's exactly what I meant too. Thanks for providing this example that makes it clearer.

I notice that it would currently not be possible to create an ARRAY[NO_DEF_EXP], since the call to the creation procedure is not under the programmer's control.

What about adding the following to ARRAY (or SPECIAL?)

class
  ARRAY[T]

feature
  create_ith_object(ith: INTEGER): T
  do
    create result.default_create
  end

That would allow programmers, taking your example, to write

class
  ARRAY_OF_NO_DEF_EXP[T]
  inherit
    ARRAY
    redefine
      create_ith_object
  end

feature

create_ith_object(ith: INTEGER): T
  do
    create result.make(arg1, arg2,...)
  end

There is probably a way to make this better with TUPLE but that's the most general form I could think of.

Regards,
David Le Bansais.