Re: Experimental features

From: Date: Thu, 06 Oct 2022 16:41:21 +0000
Subject: Re: Experimental features
References: 1 2 3 4 5 6 7 8  Groups: php.internals 
Request: Send a blank email to internals+get-118769@lists.php.net to get a copy of this message
> On 6 Oct 2022, at 16:06, Rowan Tommins <rowan.collins@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

« previous php.internals (#118769) next »