xp-framework/rfc

Path to XP7

thekid opened this issue · 46 comments

Scope of Change

This RFC describes the path towards XP 7.0

Rationale

Multiple big changes will be introduced. This document holds the roadmap; and what migrations will be necessary when.

Functionality

What needs to change

  • We need to get rid of our base lang.Object / lang.Generic - see #297 (comment)
  • While $instance->getClass() can be replaced by typeof($instance) we need to introduce a shortcut for $instance->getClassName() as core functionality nameof().
  • We need to remove the null class and xp::null()
  • We need to remove extension methods from the core
  • We need to remove reflection from the core (-> library)
  • We need to remove process control and threading from the core (-> library)
  • We need to remove wrapper types from the core (-> library)
  • We should remove uses() completely
  • We should remove support for RFC #37 as well as for classes in global namespace being aliased to their namespaced equivalents (just use namespaces!)
  • We need to remove everything but the bare minimum from XP core - see RFC #296
  • We should add support for variadics (and thus require PHP 5.6 minimum)
  • Add ideas for object kinds supporting extension methods (e.g. https://github.com/xp-forge/partial). Think about need for generics and create()

Roadmap

Release Changes relevant for XP 7.0
6.0.0 _Starting point_
6.1.0 _The preparation release_ - Core: Trait reflection support, deprecate uses() and raise(), Libraries: Introduce new better reflection API (https://github.com/xp-forge/mirrors)
6.2.0 _The null handling release_ - Core: Deprecate delete(), xp::null() - not commonly used anyways, think about introducing util.Optional (from https://github.com/xp-forge/sequence) *
6.3.0 _The naming release_ - Core: Deprecate xp::nameOf(), introduce nameof(), support for type unions, lang.Value interface (see RFC #297). Deprecate lang.types, boxing/unboxing, Libraries: Introduce new concept for wrapper types that don't and won't nameclash with PHP, to be used by e.g. remote or rdbms
6.4.0 _The namespaces release_ - Core: Remove uses() and raise(), now supports namespace-only classes, deprecate using create() for anything other than generics, deprecate this(), long array syntax in both annotations and code
6.5.0 _Enter PHP 5.5_ - Core: Require PHP 5.5, remove delete(). Deprecate ensure() which is replaced by finally. Libraries: Unittests and logging will be extracted (see RFC #293 and RFC #301).
6.6.0 _Enter PHP 5.6_ - Core: Suggest PHP 5.6 minimum, support variadics, remove xp::nameOf(), xp::null(), this(), xp::error() (the latter is not commonly used and can be replaced by exceptions). Libraries: Extract collections library
6.7.0 _The core minimizing release_ - Extract most libraries leaving us ony with lang, io and util. Remove xp::reflect() which has been deprecated for more than a year
6.8.0 _The cleanup release_ - Introduce seven branch, refactor code to work without extracted APIs, forward compatible adjustments, cleanup
6.9.0 _The error handling release_ Wrap native exceptions, remove ensure().
6.10.0 _New XP runners_ Integrate support for RFC #303 subcommands
7.0.0 _Target_: Require PHP 5.6 minimum, suggest PHP 7.0

Security considerations

Speed impact

Dependencies

  • XP 6.0.0 - 2015-02-08
  • XP 6.1.0 - 2015-04-06
  • XP 6.2.0 - 2015-05-05
  • XP 6.3.0 - 2015-06-02
  • XP 6.4.0 - 2015-07-12
  • XP 6.5.0 - 2015-08-22
  • XP 6.6.0 - 2015-11-23
  • XP 6.7.0 - 2015-12-09
  • XP 6.8.0 - 2015-12-20
  • XP 6.9.0 - 2015-12-24 🎄
  • XP 6.10.0 - 2016-01-10

Related documents

Places using xp::null():

$ grep -Hirn xp::null src/main/|cut -d ':' -f 1|sort|uniq
src/main/php/lang.base.php
src/main/php/lang/ClassLoader.class.php
src/main/php/lang/Process.class.php
src/main/php/lang/Wildcard.class.php
src/main/php/lang/XPClass.class.php
src/main/php/unittest/TestResult.class.php
src/main/php/unittest/web/WebTestCase.class.php
src/main/php/util/CompositeProperties.class.php
src/main/php/util/Filters.class.php
src/main/php/util/cmd/Console.class.php

Places using xp::error():

$ grep -Hirn xp::error src/main/|cut -d ':' -f 1|sort|uniq
src/main/jay/webservices/json/json.jay
src/main/php/io/File.class.php
src/main/php/io/ZipFile.class.php
src/main/php/lang.base.php
src/main/php/lang/types/Character.class.php
src/main/php/lang/types/String.class.php
src/main/php/util/Hashmap.class.php

_The core functionality raise is now deprecated in 6.1.0 and will be removed in 6.4.0._ The original idea to introduce it was to only load exceptions raised in seldomly executed code paths lazily. With namespaces, this is always the case. Thus, the function has become obsolete.

_The uses statement is now deprecated in 6.1.0 and will be removed in 6.4.0._ This means also classes in the global namespace which are aliased to fully qualified names as well as package classes from RFC #37 are considered deprecated.

On PHP 5.6

The above plan states XP 6.6.0 will require PHP 5.6 as its minimum version. This was chosen instead of PHP 5.5 for the following reasons:

Availability

PHP 5.6 was originally released in late August 2014. By the time XP 6.6.0 is released:

HHVM

HHVM 3.5.0 matches PHP 5.6 - see http://3v4l.org/s50F2#vhhvm-341

Features

On top of the following XP-relevant PHP features in PHP 5.5

  • Finally - replaces ensure()
  • Generators - makes code "flow"
  • T::class - replaces string references to classes
  • Non-scalar iterator keys - comes in handy for util.collections

....it also supports:

  • use function and use const - will be helpful in introducing library functions
  • Variadics and arg unpacking - finally, no more func_get_args() and call_user_func_array()

...and contains a fix for PHP bug #66608 (Incorrect behavior with nested "finally" blocks).

_The core functionality delete is now deprecated in 6.2.0 and will be removed in 6.5.0_. Simply use the language construct unset instead, which also accepts variadics.

_The core functionality xp::null() is now deprecated in 6.2.0 and will be removed in 6.6.0._. If you need null-safe handling, you can use the cast() core functionality or the ?: operator.

$ xp -w '$period= ...; return cast($period->endDate(), "util.Date")'
Uncaught exception: Exception lang.ClassCastException (Cannot cast NULL to util.Date)
# ...

$ xp -w '$period= ...; return $period->endDate() ?: Date::now()'
2015-04-25 13:55:47+0200

Criticism on the Optional class in Java:

Maybe we should think about this a bit more before introducing it to the framework

Naming

On renaming the wrapper types (see the reserving more types and reserving even more types RFCs, the following are now all reserved:

int, float, bool, string, true, false, null, resource, object, scalar, mixed, numeric

Since class names in PHP are case insensitive this means we'll to rename some prominent classes in the XP Framework:

core

  • With the "rebase" RFC #297 we suggest to remove the base class lang.Object
  • xp::null() is already deprecated and scheduled for removal
  • The Primitive class provides methods for boxing and unboxing. These will also be deprecated and removed: wrapperClasss(), unboxed(), boxed().

wrappers

  • We could use use short names for strings like Python and lang.types.String => lang.types.Str
  • We could add 32 to Float and Integer - lang.types.Float => lang.types.Float32 and lang.types.Integer => lang.types.Int32 (while the latter doesn't really conflict it would be done for consistency stakes)
  • Alternatively, we could rename the Float wrapper type to Single as done in C#

By removing the class aliasing for lang.types.* in lang.base.php and the wrapperClasss(), unboxed(), boxed() methods from Primitive, the sequence library runs once again with PHP 7:

Timm@slate ~/devel/xp/sequence [master]
$ XP_RT=7.0 unittest src/test/php/
# ...

✓: 496/496 run (0 skipped), 496 succeeded, 0 failed
Memory used: 3090.66 kB (3409.80 kB peak)
Time taken: 0.037 seconds

The "Object" name has not been reserved yet, though.

_The wrapper types in lang.types , primitive boxing and unboxing are now deprecated in 6.3.0_. The new wrapper type library is https://github.com/xp-forge/wrappers

_The core functionality xp::nameOf() is now deprecated in 6.3.0 and will be removed in 6.6.0._ Simply use the new nameof() instead.

PHP 7.0.0 alpha1

Following PHP7's first alpha - see http://php.net/archive/2015.php#id2015-01-11-6 - we've created a release which passes all tests but those where it's clear we won't have compatibility, like with the String and Float wrapper types:

https://github.com/xp-framework/core/releases/tag/v6.3.1

Please note the XP6 series will not support PHP7 officially: It reserves the name object , which clashes with our root class lang.Object . However, PHP7 alpha 1 does not yet raise an error if this class name is used.

SDK support ✅

These SDK parts support PHP7:

Library support ✅

The first libraries to support PHP7 are:

All of them allow failures for PHP 7 as long as it's not final yet.

PHP7 badge:

[![Supports PHP 7.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_0plus.png)](http://php.net/)

Supports PHP 7.0+

_The pre-namespace class loading is no longer supported in 6.4.0_. No more uses(), now more support for package-qualified and global namespace classes as fully qualified class names.

See xp-framework/core#88

_The raise() core function is longer supported in 6.4.0_. It was related to pre-namespace class loading, lazily loads exception and then throws it. No longer necessary now that we are using the PHP builtin class loading, which is lazy by default.

See xp-framework/core#89

_The core functionality create() can now only be used to create generics in 6.4.0_. The second usecase, create(new T())->method() is replaced by PHP 5.4's syntactic support for (new T())->method().

See xp-framework/core#91

The wrapper type library has its first release, 0.1.0. In it:

package lang.types {
  public abstract class lang.types.Num
  public final class lang.types.Int8       // "Byte", -128 to 127
  public final class lang.types.Int16      // "Short", -32768 to 32767
  public final class lang.types.Int32      // "Int", -2^31 to (2^31)- 1
  public final class lang.types.Int64      // "Long", -2^63 to (2^63)- 1
  public final class lang.types.Single     // "Float", -3.4 x 10^38 to +3.4 x 10^38
  public final class lang.types.Double     // "Double", ±5.0 x 10^324 to ±1.7 x 10^308
  public final class lang.types.Str        // "String"
}

The reflection replacement library has now reached 1.0.0, fully supporting:

  • PHP 5.6+
  • PHP 7.0alpha2+ and its scalar and return type hinting
  • HHVM 3.5+ and its HACK language

_Heads up: XP 6.5.0 will require PHP 5.5.0 minimum!_ Unofficially (meaning: tests will no longer verify its functionality), XP 6.5.0 will still run on PHP 5.4.X, as none of the code in src/main uses PHP 5.5 features yet, but do upgrade!

See xp-framework/core#97 and xp-framework/core#98

_The delete() core function is longer supported in 6.5.0._ It can be replaced by using the language construct unset.

_The ensure() core functionality is deprecated in 6.5.0._ It can be replaced by the PHP 5.5 language construct finally:

Before
try {
  $file->write(...);
} catch (\lang\Throwable $e) {
  // Empty
} ensure($e); {
  $file->close();
  if ($e) throw $e;
}
After
try {
  $file->write(...);
} finally {
  $file->close();
}
Before
try {
  $file->write(...);
} catch (\lang\Throwable $e) {
  $cat->warn('Could not write to file');
} ensure($e); {
  $file->close();
  if ($e) throw $e;
}
After
try {
  $file->write(...);
} catch (\lang\Throwable $e) {
  $cat->warn('Could not write to file');
  throw $e;
} finally {
  $file->close();
}

See xp-framework/core#97

_You are encouraged to use ::class for newinstance() and in annotations as of XP 6.5.0_. Instead of providing the class name in dotted form, import via use and then use PHP's native name resolution.

$instance= newinstance(Runnable::class, [], [
  'run' => function() { ... }
]);

#[@test, @expect(IllegalArgumentException::class)]
public function negative_test() {
  // ...
}

_The this() core function is longer supported in 6.6.0_. It's been obsoleted by syntactic support in PHP:

// Before
$first= this($class->getMethods(), 0);

// After
$first= $class->getMethods()[0];

See https://wiki.php.net/rfc/functionarraydereferencing (implemented in PHP 5.4).

_The xp::error() core function is longer supported in 6.6.0_. Replace by throwing exceptions in the spirit of PHP 7, which has done away with most fatal errors.

See https://wiki.php.net/rfc/catchable-call-to-member-of-non-object and https://wiki.php.net/rfc/engine_exceptions_for_php7

_The xp::null() core function is longer supported in 6.6.0._. Replace by the "real" null (and then check for it) or use the sequence library's Optional class.

_The xp::nameOf() core function is longer supported in 6.6.0_ and has been superseded by nameof($instance).

_The util.collections package is deprecated in 6.6.0_. It has been extracted from core. Its development will continue inside https://github.com/xp-framework/collections

_Quite a bunch of APIs are deprecated (but not removed) in XP 6.7.0_ and have been extracted. This means development will continue in the separate places, and the code will be removed from XP core in 7.0.0.

The relevant changelog entry:


xp::reflect() has been deprecated since September 2014, and can be replaced seamlessly by literal().

These places need to be fixed:

  • compiler
    xp/compiler/src/main/php/xp/compiler/JitClassLoader.class.php:166: if (isset(\xp::$cl[$class])) return \xp::reflect($class);
    xp/compiler/src/main/php/xp/compiler/types/Scope.class.php:257: class_exists(\xp::reflect($qualified), false) ||
    xp/compiler/src/main/php/xp/compiler/types/Scope.class.php:258: interface_exists(\xp::reflect($qualified), false) ||
    xp/compiler/src/test/php/net/xp_lang/tests/execution/source/ClassDeclarationTest.class.php:135: $this->assertEquals('demo\SourceClassInPackage', \xp::reflect($class->getName()));
    xp/compiler/src/test/php/net/xp_lang/tests/execution/source/ClassDeclarationTest.class.php:146: $this->assertEquals('demo\SourcePackageClassInPackage', \xp::reflect($class->getName()));
  • doclet
    Binary file xp/doclet/src/main/php/text/doclet/RootDoc.class.php matches
  • rdbms
    xp/rdbms/src/main/php/rdbms/Peer.class.php:167: return self::getInstance(\xp::reflect($classname));
  • webservices
    xp/webservices/src/main/php/webservices/soap/native/NativeSoapClient.class.php:213: $this->map[$qname->localpart]= \xp::reflect($class->getName());
  • xml
    xp/xml/src/main/php/xml/Tree.class.php:36: $this->nodeType= \xp::reflect('xml.Node');

XP7 branch

Now that PHP7 is out on the one hand and we're getting quite close to the final stripped down stadium of XP core, we could create a branch in xp-framework/core and start development on the 7.X code base.

https://github.com/thekid/core/tree/seven

⚠️ There most probably will no longer be a remote library when XP7 comes out, see XP RFC 0304

XP 6.10.0 has been released. It contains support for RFC-303 style runners, which bring a new "TL;DR" style for usage messages:

xp-help

Switch branches

One of the next steps will be to switch branches:

  • Master -> Six
  • Seven -> Master
  • Delete "Seven" branch

_Master of xp-framework/core is now at 7.0.0-dev_

✅ Changed all libraries to use nameof() instead of getClassName(), see xp-framework/core#120

Interesting PHP 7.1 feature: The void return type: https://wiki.php.net/rfc/void_return_type

_Other than xp-framework/core#57, I think we're all set for XP7_ - need to decide whether this should go in or not.

Decided to implement basic hack language support in xp-framework/core#123 (see also #308)

Mind changes

XP 7 -> PHP 7

I decided against this after finding out Debian wasn't going to provide PHP 7 until 2017. Lots of production systems inside companies are just making the step towards jessie, which gives us PHP 5.6 (/cc @kiesel @mikey179)

We need to remove reflection from the core (-> library)

This has not happened. I decided to leave this in until XP8, as the mirrors library isn't breaking any speed records, and I haven't succeeded in fixing this yet.

We need to remove process control and threading from the core (-> library)

I haven't felt this is necessary after all, also moving this until a later release.

Think about need for generics and create()

At the moment, there are still some libraries benefiting from generics, so I decided to keep them. It remains to be seen whether e.g. xp-forge/partial has the potential to replace them. Maybe something similar to Hack's type constants?

Coming from XP 6.0, and migrating to current XP 6-master as preparation for XP 7, here's the list of removed core functionality

  • xp::nameOf()
  • xp::null() & null class
  • xp::reflect()
  • xp::error()
  • uses()
  • raise()
  • ensure()
  • delete()
  • this()
  • create() no longer supports Generic
  • Omnipresent classes no longer aliased to short names