Ephemeral classes

by Manu (modified: 2010 Feb 26)

I've recently been toying with the idea of ephemeral classes. An ephemeral class is a class which does not have attributes. The immediate benefits of such classes is that their features can be used for objectless calls, the same way we can access constants or external features. For those not familiar to Eiffel, the features of ephemeral classes can be seen as static methods.

For example:

ephemeral class A feature objectless_feature do ... end end class TEST feature g do {A}.objectless_feature end end

Another benefit of such classes is that their features can be directly used for callbacks by some external C/C++ code without having the need for creating a C wrapper for calling back the Eiffel code.

The concept is not yet implemented in EiffelStudio as it is not just a matter of checking the absence of attributes but also to adapt the code generation not to rely on a Current object.

This is something that will most likely be submitted for adoption for the ECMA Eiffel language specification. But before that, I'd like to hear what you think about this!

Happy Eiffeling,

Manu

Comments
  • Zoran Simic (7 years ago 27/2/2010)

    Great idea

    I think this is a great idea. Many classes are in this situation, and we have to employ various artificial technicalities to use them more or less elegantly (inheritance mostly).

    This would be a great way of not having to abuse inheritance all over the place for things like constants, utility features etc.

  • Colin Adams (7 years ago 27/2/2010)

    Why ephemeral?

    I think it is a good idea. But why the name ephemeral? I suppose the connection is with storables. And are the keyword frozen and deferred supposed to be allowed also? The combination of frozen ephemeral sounds particularly odd to me.

    • Manu (7 years ago 28/2/2010)

      The name was suggested during an ECMA meeting. It might not be the final name, but for the moment this is what we will use for testing this.

      • Peter Gummer (7 years ago 1/3/2010)

        Stateless classes

        (This idea came to mind while reading Alexander's post below.)

        Rather than "ephemeral classes", I think a better name would be "stateless classes".

        Eiffel already uses too many idiosyncratic keywords, which I suspect may be a barrier to its wider acceptance: "deferred" vs "abstract", "void" vs "null", etc. The word "stateless" has been widely used for a long time.

        • Alexander Kogtenkov (7 years ago 1/3/2010)

          Shall we introduce new entities?

          It looks like I failed to highlight that apart from stateless property of a class that can be used for objectless calls the other one is lack of identity. Indeed stateless class still can be used to program an application with the behaviour that depends on the objects (the example is simplified, compared to real life, but should give an idea): class TRAFFIC_LIGHT_COLOR inherit ANY redefine out end create {TRAFFIC_LIGHT} default_create feature -- Output out: STRING -- <Precursor> local controller: TRAFFIC_LIGHT do create controller if Current = controller.green then Result := "green" elseif Current = controller.yellow then Result := "yellow" else Result := "red" end end end class TRAFFIC_LIGHT inherit ANY redefine default_create end feature -- Creation default_create do light := red end feature -- Access light: TRAFFIC_LIGHT_COLOR -- Current light feature -- Modification turn_green do light := green end turn_yellow do light := yellow end turn_red do light := red end feature -- Allowed values of `light' green: TRAFFIC_LIGHT_COLOR once ("PROCESS") create Result end yellow: TRAFFIC_LIGHT_COLOR once ("PROCESS") create Result end red: TRAFFIC_LIGHT_COLOR once ("PROCESS") create Result end end t: TRAFFIC_LIGHT a, b: TRAFFIC_LIGHT_COLOR ... create t a := t.light t.turn_green b := t.light io.put_string (a.out) -- Prints "red" io.put_string (b.out) -- Prints "green"
          As the example demonstrates we need to get rid of object identity to allow objectless calls.

          The last property is already present in expanded classes without attributes. If we follow Occam's razor, there is no need to invent a new notion. Otherwise we can quickly get into the situation like "Doesn't Y already provide X? - Yes, it does, but we added Z and use it instead."

          However, the classes that are supposed to be used in a specific way are better to be explicitly marked as such. My feeling is that the built-in Eiffel documentation system, based on note clause, is quite underused for this purpose. In particular, we may have an associated clause note state: no identity: no storable: no
          for the classes like these.

  • Colin LeMahieu (7 years ago 28/2/2010)

    I wonder how compatible the idea of ephemeral is to "exherit"-ing from existing classes; essentially associating additional functionality to objects. The use-case would be, I have some common function I apply to an integer so it should be associated with an integer.

    ephemeral class BLOCK exherit NATURAL_32 feature mix (other: BLOCK): BLOCK do Result := Current.xor (other) end end class APPLICATION feature make local op1: NATURAL_32 op2: NATURAL_32 block1: BLOCK block2: BLOCK block3: BLOCK do op1 := 0xababcdcd op2 := 0x44444444 block1 := op1 block2 := op2 block3 := block1.mix (block2) end end

    If one were to exherit from multiple classes, it would be similar to how generic conformance works. You can exherit the class as long as the object you're operating on statically conforms to the exheritance clause.

    In my opinion this would be a cleaner way to define conforming inheritance.

    To your original point, it would be nice to be able to define C callback code within Eiffel.

    • Manu (7 years ago 28/2/2010)

      This mechanism is known in the Eiffel world as reverse inheritance and was proposed many years ago. I don't have the details but this was looked at by the ECMA committee and dismissed for the time being because most likely it was not resolving a problem that users were having.

  • Alexander Kogtenkov (7 years ago 1/3/2010)

    The mechanism is ready for use

    Talking about objectless calls, we can consider how objects are used. There are 2 properties tightly bound to an object:

    1. state - attributes hold associated values
    2. identity - reference equality can tell if the objects are the same or not even if they are in the same state

    We do not care for identity of objects of expanded types. In other words we never know if an object of an expanded type is "the same object" referenced by some other entity (or an expression in general) or not.

    From the practical point of view, if we consider a boolean expressiona = bwhere type of a and b is the same stateless type (i.e. has no attributes), we can get different results if the type is reference, for example, because the equality can be preceded bycreate a create b
    but we'll always get True if the type is expanded (the equality operator above refers to the standard object equality, not to some special cases, like NaN in floating point math, discussed elsewhere).

    In the latter case there is neither state nor identity associated with an object: objects of the same expanded type without attributes cannot be distinguished in any way. Moreover, no special rules for using special entity Current are required, because it is safe to use it: there is nothing associated with it. Summarizing the above, Eiffel already has appropriate mechanism for "ephemeral" classes: they are expanded classes without attributes. Only the language specification needs to be updated to allow objectless calls on types, based on such classes.

    • Alexander Kogtenkov (7 years ago 1/3/2010)

      Clarification

      I'd like to clarify the idea of the previous message. When we talk about objectless calls, we mean that out of the 3 properties associated with objects:

      • identity
      • state
      • behaviour

      we need only one - behaviour. The other two should not be present for the calls to be safe as objectless. And this is what expanded classes without attributes provide: only behaviour without any identity or/and state. Therefore they can be used directly for the purpose raised by this topic:note identity: no state: no behaviour: yes expanded class MATH_64 feature -- Logarithm log2 (value: REAL_64): REAL_64 -- Logarithm with base 2 ... ln (value: REAL_64): REAL_64 -- Logarithm with base `e' ... lg (value: REAL_64): REAL_64 -- Logarithm with base 10 ... end

      Free bonus: the objectless features can be used in unqualified calls (if inherited, including secret inheritance), qualified objectless calls and qualified object calls:inherit {NONE} MATH_64 -- Normal inheritance can be used as well if required ... m: MATH_64 -- Can be declared if we want to avoid inheritance from MATH_64 ... x := ln (y) -- Unqualified call to inherited feature x := {MATH_64}.ln (y) -- Qualified objectless call x := m.ln (y) -- Qualified object call (the object `m' is only to make the call, it's not used by itself)

    • Manu (7 years ago 2/3/2010)

      There is one issue with having expanded class without attributes being considered ephemeral it is the one of conformance. In the case of the ephemeral class expanded class A, and having class B inherit A, you cannot write the following:

      a: A b: B a := b

      but I definitely agree that expanded classes without attributes fit the description of ephemeral classes.

      • Alexander Kogtenkov (7 years ago 2/3/2010)

        That's correct

        When this possibility is required, we can have 2 classes with the expanded one inheriting the reference: class A_REF feature ... end expanded class A inherit A_REF end
        Then the code from the example can be rewritten as a: A_REF b: B a := b
        Hopefully in practice this will not happen too often, because the idea is to detach any state and identity from an object - allowing the attachments like the above we preserve them instead.

      • Colin LeMahieu (7 years ago 22/4/2010)

        I like this notion of expanded classes without attributes being ephemeral.

        Instead of allowing objectless calls to a feature e.g. {CLASS_A}.static_call_one

        Could we just make creation of CLASS_A a no-op.

        feature local a: CLASS_A do create a a.static_call_one end

        This feature would essentially ignore the "create a" because it's not needed, there are no attributes to create. Then the optimization of not calling the memory allocator could be realized without "adding" the objectless feature call syntax.

        • Alexander Kogtenkov (7 years ago 29/4/2010)

          No need for creation instruction

          Since entities of expanded types are initialized automatically, there is no need for creation instruction (assuming that class CLASS_A is expanded) and your example simplifies to: f local a: CLASS_A do a.static_call_one end

  • Peter Gummer (7 years ago 1/3/2010)

    Inheriting from an ephemeral class

    What would happen if I write a class that inherits from an ephemeral class?

    ephemeral class A feature objectless_feature do ... end end class B inherit A end class TEST feature g local b: B do create b b.objectless_feature end end

    This would always call {A}.objectless_feature, right? No opportunity for polymorphism? Or would class B be permitted to redefine objectless_feature?

    • Alexander Kogtenkov (7 years ago 1/3/2010)

      It should not do any harm

      I believe it's OK to inherit and redefine features that are initially used as objectless. The issue is that they cannot be any longer used as objectless if the inheriting/redefining class does not ensure this property. But this does not break clients of the original objectless class, because the calls are not associated with any objects, they are bound to the class instead.

      (And if one wants to forbid such inheritance or redefinition, the class can be marked as frozen.)

  • Peter Gummer (7 years ago 4/3/2010)

    UFOs

    Alexander has clarified that ephemeral classes have no identity and no state.

    Maybe we could call instances of them UFOs: Unidentified Fleeting Objects.