> On 6 Oct 2022, at 16:06, Rowan Tommins <rowan.coll...@gmail.com> wrote:
> 
> On 06/10/2022 12:16, Alex Wells wrote:
>> A marker merely just tells the compiler "hey, allow me to use this feature 
>> right here", i.e. it denotes a piece of code as allowed to use the feature, 
>> not enable it. Effectively, all experimental features are just regular 
>> features that are "always on" and hence can be optimized the same way 
>> regular features are. The marker serves two purposes: allow simple discovery 
>> of usages (by the compiler or other tools) and force the developer to 
>> acknowledge they're using an experimental feature with an unstable 
>> API/syntax/spec.
> 
> 
> I don't really understand the distinction between "enabling" and "being able 
> to use", nor what it would mean for a feature to "experimental" but also 
> integrated fully into the language.
> 
> In general, I'm finding it quite hard to follow the idea in the abstract - 
> the definition of "feature" seems very fuzzy. Could someone give some 
> examples from another language, or concrete examples where it would be used 
> in PHP, and then work through the details of what would be expected to happen 
> in what version of PHP?
> 
> 
>> Regarding the monitoring - that is a problem that needs to be solved and 
>> there are multiple solutions: GitHub issues, corporate/public messengers 
>> (Slack?) or the internals mailing list.
> 
> 
> There are certainly ways to approach it; I'm just agreeing with a previous 
> commenter that this would need to be an explicit part of any proposal, not 
> just hand-waved away.
> 
> Regards,
> 
> -- 
> Rowan Tommins
> [IMSoP]
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
> 

I'll try my best to elaborate, although I the author of the proposal will 
likely do a better job.

A feature is generally considered any addition to the language or it's standard 
library - that could be a new set of functions, new syntax etc. Experimental 
features refer to features whose stability is "experimental".

Kotlin divides their features into four stability levels: experimental, alpha, 
beta and stable. Each of those might have their own preconditions, BC promises 
and release cycle rules. A feature with "experimental" stability level requires 
an opt-in: a piece of code that uses the new feature must be marked with an 
annotation. For example, Kotlin has recently introduced a new feature - 
unsigned integer types. This inlcudes new types and a new syntax. This is how 
you'd use them:

```kotlin
@OptIn(ExperimentalUnsignedTypes::class)
fun unsignedInt(): UInt {
    return 123u
}

@OptIn(ExperimentalUnsignedTypes::class)
fun main(args: Array<String>) {
    println(
        unsignedInt()
    )
}
```

`123u` here denotes an integer that is unsigned. The `u` part is the new 
syntax. `UInt` is the new type. Notice two `OptIn` annotations - one for the 
function which returns the new type, and the other for it's dependent. The 
second annotation is needed because of the return type - Kotlin assumes the 
return type is used, effectively assuming you're using the new type in your 
function, which requires opt-in.

This changes if `unsignedInt` returns `Int` (a regular type, not part of the 
experimental feature) instead:

```kotlin
@OptIn(ExperimentalUnsignedTypes::class)
fun unsignedInt(): Int {
    return 123u as Int     // cast UInt to Int
}

fun main(args: Array<String>) {
    println(
        unsignedInt()
    )
}
```

Notice how an opt-in is no longer needed for `main`.

If you omit the opt-in altogether, this is what the compiler (and the IDE) will 
throw at you:  `Main.kt: (7, 20): This declaration is experimental and its 
usage should be marked with '@kotlin.ExperimentalUnsignedTypes' or 
'@OptIn(kotlin.ExperimentalUnsignedTypes::class)'`

Of course, in Kotlin there also mechanism to opt-in more than just a single 
function. This can be done on file, module or even project level:
```
@file:OptIn(ExperimentalUnsignedTypes::class)
// or module-wide
sourceSets {
    someModule {
        languageSettings.optIn("org.mylibrary.OptInAnnotation")
    }
}
// or project-wide compiler flag
-opt-in=org.mylibrary.OptInAnnotation
```

////

Onto the PHP application. It's similar, although obviously due to the dynamic 
nature of the language the compiler wouldn't be able to force opt-ins nearly on 
the same level as Kotlin compiler does. This isn't to say experimental features 
can't be implemented properly in PHP.

Let's say PHP wants to experiment with a new function - `json_validate()`. The 
idea is simple: follow the regular RFC process and release the function the 
same way you would without experimental functions. The only thing that is 
needed is to mark the function as one that requires an opt-in:

```php
#[Experimental(ExperimentalLevel.WARNING)]
class ExperimentalJsonValidate {}

#[RequiresOptIn(ExperimentalJsonValidate::class)]
function json_validate($something): something {}
```

Then, any consumer of that function would be required to opt-in:

```php
#[OptIn(ExperimentalJsonValidate::class)]
function main() {
    json_validate(); // all good
}
```

If an opt-in is missing, PHP will trigger an warning (during runtime):

```php
function main() {
    json_validate(); // trigger_error('Must be opted-in', E_WARNING)
}
```

Few months after the release (let's say 8.2), PHP collects feedback and 
analyses codebases (which is easy thanks to the attribute) and decides it wants 
to change the name to `json_revalidate`. This is of course over exaggerated, 
but it's to prove the point. Just as any other change in PHP, this would 
require an RFC. If it's accepted, the change is done.

Under regular circumstances (no experimental features), such a change would 
have to at least have a deprecation notice for one minor/major release prior to 
it (so the minimum version this could be done in is 8.4). Moreover, such 
changes would usually be avoided at all costs, because this is a big breaking 
change. 

Experimental features on the other hand are explicit opt-in - users know it can 
be changed at any time, without a warning, a deprecation or anything for that 
matter, in any release. That allows the change to be done without really 
worrying of BC and also much earlier (8.3 or even 8.2.1 if you decide so). 
Also, the `#OptIn` attribute allows consumers to easily find all places where 
an experimental feature was used in case a breaking change was done.

The same concept can also be applied to new syntax - let's say generics, except 
with a more strict error (E_FATAL, for example). This has been briefly 
discussed here: https://github.com/PHPGenerics/php-generics-rfc/issues/49

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to