391 lines
10 KiB
Markdown
391 lines
10 KiB
Markdown
# 20. Opérateurs
|
|
|
|
## 20.1 Principe — V1 REQUIS — FIGÉ
|
|
|
|
Les opérateurs utilisateur ne peuvent être fournis que via un ensemble fermé d'interfaces Core compiler-known préfixées `Op`.
|
|
|
|
L'utilisateur ne peut pas inventer de nouveaux symboles opérateurs.
|
|
|
|
Les contrats `operator` :
|
|
|
|
- retournent directement leur valeur ;
|
|
- ne retournent jamais `Result` ;
|
|
- ne déclarent jamais `throws` ;
|
|
- peuvent produire des `Fault` unchecked lorsque le contrat de l'opération le prévoit ;
|
|
- peuvent documenter ces faults par une clause `faults`.
|
|
|
|
Une opération dont la précondition est statiquement prouvée fausse est rejetée à la compilation lorsque la règle du langage permet cette preuve. Une violation seulement dynamique produit le `Fault` correspondant.
|
|
|
|
## 20.2 Interfaces arithmétiques — V1 REQUIS — FIGÉ
|
|
|
|
```text
|
|
OpPositive<T>
|
|
OpNegate<T>
|
|
|
|
OpAdd<Lhs,Rhs,Out>
|
|
OpSubtract<Lhs,Rhs,Out>
|
|
OpMultiply<Lhs,Rhs,Out>
|
|
OpDivide<Lhs,Rhs,Out>
|
|
OpRemainder<Lhs,Rhs,Out>
|
|
```
|
|
|
|
Les opérations binaires peuvent être hétérogènes.
|
|
|
|
Exemples légitimes :
|
|
|
|
```text
|
|
Vector3 * float64 -> Vector3
|
|
Matrix * Vector3 -> Vector3
|
|
Timestamp + Duration -> Timestamp
|
|
Timestamp - Timestamp -> Duration
|
|
```
|
|
|
|
L'ordre compte : `A op B` est distinct de `B op A`.
|
|
|
|
## 20.3 Interfaces bitwise — V1 REQUIS — FIGÉ
|
|
|
|
```text
|
|
OpBitNot<T>
|
|
OpBitAnd<Lhs,Rhs,Out>
|
|
OpBitOr<Lhs,Rhs,Out>
|
|
OpBitXor<Lhs,Rhs,Out>
|
|
OpShiftLeft<T,Out>
|
|
OpShiftRight<T,Out>
|
|
```
|
|
|
|
Pour les primitives numériques, `& | ^` exigent les mêmes types primitifs exacts, sans promotion implicite.
|
|
|
|
Les shifts primitifs utilisent initialement `uint32` comme type de count.
|
|
|
|
Count hors largeur :
|
|
|
|
```text
|
|
statique -> erreur compilation
|
|
dynamique -> faute runtime
|
|
```
|
|
|
|
`>>` :
|
|
|
|
```text
|
|
unsigned -> logical zero-fill
|
|
signed -> arithmetic sign extension
|
|
```
|
|
|
|
Pas de `>>>`.
|
|
|
|
## 20.4 Logique booléenne — V1 REQUIS — FIGÉ
|
|
|
|
Short-circuit :
|
|
|
|
```text
|
|
!a
|
|
a && b
|
|
a || b
|
|
```
|
|
|
|
Eager :
|
|
|
|
```text
|
|
a & b
|
|
a | b
|
|
a ^ b
|
|
```
|
|
|
|
`&&`, `||` et `!` ne sont pas surchargeables.
|
|
|
|
`&`, `|`, `^` ont une sémantique intrinsèque eager pour `bool`, bitwise pour les primitives entières et peuvent utiliser les contrats `OpBit...` sur types utilisateur.
|
|
|
|
Pas de NAND/NOR natifs.
|
|
|
|
## 20.5 Égalité — V1 REQUIS — FIGÉ
|
|
|
|
```text
|
|
OpPartialEqual<Lhs,Rhs>
|
|
OpEqual<T>
|
|
Equatable<T>
|
|
```
|
|
|
|
`OpEqual<T>` renforce :
|
|
|
|
```text
|
|
OpPartialEqual<T,T>
|
|
```
|
|
|
|
et garantit contractuellement une relation d'équivalence :
|
|
|
|
```text
|
|
réflexive
|
|
symétrique
|
|
transitive
|
|
```
|
|
|
|
`Equatable<T>` est la capacité Core destinée aux APIs génériques qui ont besoin de cette égalité totale. Elle réutilise l'implémentation opérateur canonique et n'introduit ni seconde méthode `equals()` ni deuxième définition de `==` :
|
|
|
|
```text
|
|
interface Equatable<T> extends OpEqual<T> {
|
|
}
|
|
```
|
|
|
|
Ainsi, la règle générale reste inchangée : les opérateurs utilisateur sont définis uniquement via les interfaces compiler-known `Op...`, tandis que `Equatable<T>` permet d'exprimer une contrainte sémantique de haut niveau sans dupliquer l'opération.
|
|
|
|
Les `float*` conservent les comparaisons IEEE de la version normative adoptée. Comme `NaN == NaN` est faux, ils ne satisfont pas directement `Equatable<float*>` et relèvent de l'égalité partielle générale.
|
|
|
|
`!=` est toujours la négation logique de `==`, jamais une implémentation indépendante.
|
|
|
|
Les classes ne reçoivent aucune comparaison champ-à-champ automatique : elles doivent choisir explicitement leur sémantique d'égalité si elles veulent supporter `==`. L'identité de référence universelle reste distincte et s'obtient par `Object::sameIdentity(...)`.
|
|
|
|
## 20.6 Comparaison — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Core distingue l'ordre partiel de l'ordre total :
|
|
|
|
```text
|
|
public enum PartialOrdering {
|
|
Less,
|
|
Equal,
|
|
Greater,
|
|
Unordered
|
|
}
|
|
|
|
public enum Ordering {
|
|
Less,
|
|
Equal,
|
|
Greater
|
|
}
|
|
```
|
|
|
|
Interfaces opérateur :
|
|
|
|
```text
|
|
OpPartialCompare<Lhs,Rhs>
|
|
-> PartialOrdering
|
|
|
|
OpCompare<T>
|
|
-> Ordering
|
|
```
|
|
|
|
`OpCompare<T>` garantit un ordre total. Les floats utilisent l'ordre partiel pour leurs opérateurs généraux en raison de `NaN`; les entiers peuvent utiliser l'ordre total.
|
|
|
|
`Ordering::Equal` signifie équivalence dans la relation d'ordre considérée. Il ne doit pas être confondu automatiquement avec l'égalité générale `==`.
|
|
|
|
Les contrats applicatifs `Comparable<T>` et `Comparator<T>` des collections ordonnées utilisent `Ordering` et sont définis au chapitre 22.
|
|
|
|
## 20.7 Comparaisons hétérogènes — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Saselang doit conserver la possibilité d'égalité/comparaison hétérogène.
|
|
|
|
La forme exacte des paramètres génériques et les règles de symétrie automatique doivent encore être formalisées pour éviter les implémentations concurrentes incohérentes.
|
|
|
|
## 20.8 Ownership des implémentations opérateur — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Direction :
|
|
|
|
- normalement l'implémentation appartient au type nominal de gauche ;
|
|
- si le LHS est une primitive/Core sealed non extensible, le type nominal de droite peut fournir une forme inverse explicitement permise ;
|
|
- un troisième package ne peut pas définir arbitrairement un opérateur entre deux types externes ;
|
|
- une seule implémentation canonique par `(operator,Lhs,Rhs)`.
|
|
|
|
Les détails doivent être alignés sur le resolver des packages.
|
|
|
|
## 20.9 Indexation — V1 REQUIS — FIGÉ
|
|
|
|
```text
|
|
OpIndex<Index,Read>
|
|
OpIndexMut<Index,Write>
|
|
```
|
|
|
|
Les deux contrats sont indépendants.
|
|
|
|
Syntaxe :
|
|
|
|
```text
|
|
container[index]
|
|
container[index] = value
|
|
```
|
|
|
|
Les séquences standard utilisent initialement `uint64` comme index.
|
|
|
|
D'autres index numériques pourront être supportés ultérieurement sans modifier la largeur de `uint64`.
|
|
|
|
Un type utilisateur peut utiliser n'importe quel type d'index pertinent.
|
|
|
|
## 20.10 Map — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
Le contrat des maps est défini au chapitre 22.
|
|
|
|
L'indexation est stricte :
|
|
|
|
```text
|
|
map[key] -> V
|
|
```
|
|
|
|
La clé doit exister ; une absence dynamique produit `KeyNotFoundFault`.
|
|
|
|
L'accès conditionnel est explicite et distinct :
|
|
|
|
```text
|
|
map::get(key) -> Option<V>
|
|
```
|
|
|
|
`OpIndexMut<K,V>` remplace uniquement la valeur d'une clé existante ; l'affectation indexée n'insère jamais implicitement une nouvelle clé.
|
|
|
|
## 20.11 Affectation — V1 REQUIS — FIGÉ
|
|
|
|
`=` n'est pas une expression.
|
|
|
|
Interdits :
|
|
|
|
```text
|
|
if (a = b) { ... }
|
|
x = (a = b);
|
|
a = b = c;
|
|
```
|
|
|
|
## 20.12 Affectations composées — V1 REQUIS — FIGÉ
|
|
|
|
```text
|
|
+= -= *= /= %=
|
|
&= |= ^=
|
|
<<= >>=
|
|
```
|
|
|
|
Elles n'ont aucun `Op...` propre et ne sont donc pas surchargeables directement.
|
|
|
|
Elles sont composées de :
|
|
|
|
```text
|
|
lecture
|
|
+ opérateur fondamental surchargeable
|
|
+ réaffectation
|
|
```
|
|
|
|
Le résultat de l'opération doit être assignable exactement à la destination.
|
|
|
|
Aucune conversion implicite ne doit être inventée pour rendre l'affectation composée valide.
|
|
|
|
## 20.13 `is` — V1 REQUIS — FIGÉ
|
|
|
|
`is` teste l'appartenance d'une valeur à un type polymorphe ou à l'un de ses sous-types runtime.
|
|
|
|
```text
|
|
value is Type
|
|
```
|
|
|
|
Pour une instance runtime de `Labrador` avec `Labrador extends Dog` et `Dog extends Animal` :
|
|
|
|
```text
|
|
value is Animal // true
|
|
value is Dog // true
|
|
value is Labrador // true
|
|
```
|
|
|
|
`is` est utilisable sur les classes et les interfaces lorsqu'un polymorphisme runtime existe. Il est interdit sur les types sans polymorphisme runtime tels que les primitives numériques, `char`, les structs, les enums, les tuples ou les unions.
|
|
|
|
`is` n'est pas surchargeable.
|
|
|
|
Dans une branche dont la condition positive prouve `value is Type`, le compilateur raffine `value` vers `Type` dans le scope correspondant. Le raffinement cesse avec ce scope.
|
|
|
|
Saselang n'introduit pas `is not` : la négation générale s'écrit explicitement :
|
|
|
|
```text
|
|
!(value is Type)
|
|
```
|
|
|
|
## 20.14 `instanceof` — V1 REQUIS — FIGÉ
|
|
|
|
`instanceof` teste le **type de classe runtime exact**.
|
|
|
|
```text
|
|
value instanceof ConcreteClass
|
|
```
|
|
|
|
Pour une instance runtime exacte de `Labrador` :
|
|
|
|
```text
|
|
value instanceof Animal // false
|
|
value instanceof Dog // false
|
|
value instanceof Labrador // true
|
|
```
|
|
|
|
`instanceof` est utilisable uniquement avec une classe concrète non abstraite. Il est interdit avec une interface, une classe abstraite et tout type sans identité de classe runtime.
|
|
|
|
`instanceof` n'est pas surchargeable.
|
|
|
|
Une branche positive raffine la valeur vers la classe concrète testée et établit en plus que son type runtime est exactement cette classe.
|
|
|
|
Saselang n'introduit pas `not instanceof` :
|
|
|
|
```text
|
|
!(value instanceof ConcreteClass)
|
|
```
|
|
|
|
`is` et `instanceof` coexistent parce qu'ils ont deux sémantiques différentes : appartenance à une hiérarchie pour `is`, identité exacte de classe runtime pour `instanceof`.
|
|
|
|
## 20.15 `bitcast<T>` — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
```text
|
|
bitcast<T>(value)
|
|
```
|
|
|
|
est un intrinsic compiler-known, pas un opérateur.
|
|
|
|
Il préserve exactement les bits et exige des tailles compatibles.
|
|
|
|
Il ne réalise aucune conversion numérique.
|
|
|
|
Certains bitcasts sont sûrs lorsque tout motif de bits destination est valide ; d'autres nécessiteront `unsafe`.
|
|
|
|
Le tableau exact doit être lié au modèle mémoire.
|
|
|
|
## 20.16 Appel `()` — V1 REQUIS — FIGÉ EN PRINCIPE
|
|
|
|
`()` est une construction d'appel du langage, pas un opérateur utilisateur.
|
|
|
|
Il n'est pas prévu de fournir un `OpCall` général.
|
|
|
|
Les fonctions, closures/lambdas futures seront appelables par définition de leur type, pas en surchargeant arbitrairement `()` sur n'importe quel objet.
|
|
|
|
## 20.17 Précédence — V1 REQUIS — FIGÉ
|
|
|
|
Du plus fort au plus faible :
|
|
|
|
```text
|
|
1. qualification / membre . ::
|
|
2. appel / indexation () []
|
|
3. préfixes +x -x !x ~x
|
|
4. multiplicatifs * / %
|
|
5. additifs + -
|
|
6. shifts << >>
|
|
7. relation / type < <= > >= is instanceof
|
|
8. égalité == !=
|
|
9. bitwise AND &
|
|
10. bitwise XOR ^
|
|
11. bitwise OR |
|
|
12. logique short-circuit AND &&
|
|
13. logique short-circuit OR ||
|
|
```
|
|
|
|
`bitcast<T>(...)` suit la syntaxe d'appel et n'a pas sa propre précédence.
|
|
|
|
`=` et les affectations composées ne figurent pas dans cette hiérarchie puisqu'elles ne produisent pas de valeur.
|
|
|
|
## 20.18 Associativité — V1 REQUIS — FIGÉ
|
|
|
|
Les opérateurs binaires arithmétiques/bitwise/logiques sont associatifs syntaxiquement à gauche.
|
|
|
|
Les préfixes s'imbriquent depuis la droite.
|
|
|
|
Les comparaisons sont non associatives :
|
|
|
|
```text
|
|
a < b < c -> interdit
|
|
a == b == c -> interdit
|
|
```
|
|
|
|
Écrire explicitement :
|
|
|
|
```text
|
|
a < b && b < c
|
|
```
|
|
|
|
---
|