Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generics optimization #193

Closed
thekid opened this issue Oct 17, 2011 · 1 comment
Closed

Generics optimization #193

thekid opened this issue Oct 17, 2011 · 1 comment

Comments

@thekid
Copy link
Member

thekid commented Oct 17, 2011

Scope of Change

Generics will be optimized.

Rationale

  • Improve performance
  • Enable reflection for generics
  • Enable reflective creation of generics
  • Support primitives a generic arguments

Functionality

Currently, generics are implemented as follows:

  • A: A __generic instance member is required inside the declaration.
    It will hold an array of the component types.
  • B: The methods working with generics are required to take care of
    the type checks.
  • C: The create() core functionality takes care of instantiating the
    generics, populating the __generic member with the given types'
    names.

Example (abbreviated):

<?php
  class Vector extends Object {
    public $__generic;                                  // A

    public function add($value) {
      if (!$value instanceof $this->__generic[0]) {     // B
        throw new IllegalArgumentException('...');
      }
      // ...
    }
  }

  $v= create('new Vector<lang.types.String>()');        // C
?>

This has the following downsides:

  • The declaration is quite verbose and introduces a bunch of boilerplate
    code for the manual component type verification.
  • At runtime, two generics, e.g. a vector of strings and one integers,
    are "instanceof"-compatible
  • There is no way to type-hint a generic, verifying a vector's component
    type is string would mean manually accessing its __generic member.

Plan

A generic instance should be created at runtime named with unique name
created of the base and component types. A class has two names, one that
is reported by XPClass::getName() (F) and one used literally (L):

<?php
  // Creates a class named: 
  // F: "util.collections.Vector`1[lang.types.String]"
  // L: "Vector··String"
  $ve= create('new Vector<lang.types.String>()');

  // Creates a class named: 
  // F: "util.collections.HashTable`2[lang.types.String,lang.Generic]"
  // L: "HashTable··String¸Generic"
  $ht= create('new HashTable<lang.types.String, lang.Generic>()');

  // Creates a class named: 
  // F: "util.collections.Stack`1[string]"
  // L: "Stack··þstring"
  $st= create('new Stack<string>()');
?>

The same generation process happens for all generic interfaces these
classes implement and the generic base classes they extend.

The middle dot (·, Alt-Gr + "." in Cygwin) is used in the XP Framework
for generated classes and in fully qualified names (see xp-framework/rfc #37). The
cedil sign (¸, Alt-Gr + "´" in Cygwin) is used to separate the components.

Declaration

To declare a generic class using the XP framework, we will resort to
annotations:

<?php
  #[@generic(self= 'K, V', interfaces= array('Map' => 'K, V')))]
  class HashTable extends Object implements Map {

    #[@generic(params= 'K, V')]
    public function put($key, $value) { ... }

    #[@generic(params= 'K')]    
    public function get($key) { ... }

    #[@generic(return= 'V[]')]
    public function values() { ... }

    public function toString() { ... }
  }
?>

In XP language, this needn't be done as it syntactically supports generics:

<?php
  public class HashTable<K, V> implements Map<K, V> {

    public void put(K $key, V $value) { ... }

    public V get(K $key) { ... }

    public V[] values() { ... }

    public string toString() { ... }
  }
?>

Instantiation

To instantiate generics, the create() core functionality needs
to be used. The inner workings are as follows:

  1. Parse string specifying type into class and parameters
  2. Compose unique name
  3. If this class exists, instantiate and return
  4. For all interfaces, perform generation
  5. Generate class extending lang.Object
  6. For all methods generate delegation
  7. Instantiate and return

What we will end up with is the following:

<?php
  interface Map··String¸Object {
    public function put(String $key, Object $value);
    public function get(String $key);
    public function values();
  }

  class HashTable··String¸Object extends Object implements Map··String¸Object {
    private $delegate;

    public function __construct() {
      $this->delegate= new HashTable();
    }

    public function put(String $key, Object $value) {
      $this->delegate->put($key, $value);
    }

    // ...
  }
?>

Reflection

Whether a type is a generic instance should be determinable at runtime:

<?php
  // Will display: 
  //   Arguments: [
  //     0 => lang.XPClass<lang.types.String>
  //   ]
  $class= create('new Vector<String>()')->getClass();
  if ($class->isGeneric()) {
    Console::writeLine('Arguments: ', $class->genericArguments());
  }
?>

Reflection on generic definitions should also be possible:

<?php
  // Will display:
  //   Components: [
  //      0 => "T"
  //   ]
  $class= XPClass::forName('util.collections.Vector');
  if ($class->isGenericDefinition()) {
    Console::writeLine('Components: ', $class->genericComponents());
  }
?>

Also, reflective creation of generic types should be possible:

<?php
  $class= XPClass::forName('util.collections.Vector');
  $generic= $class->newGenericType(array(XPClass::forName('lang.types.String')));

  // ...and then use newInstance() methods
  $vector= $generic->newInstance();
?>

Discovering the definition type:

<?php
  // Will display:
  //   Definition: lang.XPClass<util.collections.Vector>
  $class= create('new Vector<String>()')->getClass();
  if ($class->isGeneric()) {
    Console::writeLine('Definition: ', $class->genericDefinition());
  }
?>

Type restrictions

The generic types can now be used in parameter type hints, although
somewhat ugly:

<?php
  public function dump(List··String $l) { ... }
?>

Security considerations

n/a

Speed impact

Faster.

Dependencies

xp-framework/rfc #197

Related documents

@thekid thekid closed this as completed Oct 17, 2011
@thekid thekid mentioned this issue Jan 15, 2012
thekid added a commit to xp-framework/xp-framework that referenced this issue Oct 28, 2012
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/remote that referenced this issue Nov 10, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/doclet that referenced this issue Nov 10, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/zip that referenced this issue Nov 10, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/rdbms that referenced this issue Nov 11, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/csv that referenced this issue Nov 11, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/parser that referenced this issue Nov 11, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/rest that referenced this issue Nov 11, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/scriptlet that referenced this issue Nov 11, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/imaging that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/ftp that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/http that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/ldap that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/mail that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/news that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/irc that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/sieve that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/webdav that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/spelling that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/xml that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
thekid added a commit to xp-framework/telephony that referenced this issue Nov 12, 2013
# They yielded a php.stdClass instance instead of the one to be instantiated,
# which would result in "Fatal error: Call to undefined method stdClass::X()"
# when any method X would be called
# See xp-framework/rfc#193
@thekid
Copy link
Member Author

thekid commented Nov 13, 2013

The $__generic-style generics (BC with < 5.8) has been removed in XP 6 (see RFC #172)

thekid added a commit to thekid/core that referenced this issue Aug 13, 2014
Left-over from first generic implementation, see xp-framework/rfc#193,
which was dropped around three years ago and removed back in Nov 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant