This commit is contained in:
2026-09-13 10:20:16 +02:00
parent 019c8ad335
commit b72193d656
38 changed files with 1523 additions and 837 deletions

View File

@@ -135,9 +135,9 @@ Les indices d'une sous-slice sont relatifs à la slice source.
Les interfaces décrivent des capacités réellement garanties. Les classes/structs génériques fournissent le stockage et l'implémentation.
Saselang ne retient pas le modèle d'opérations optionnelles qui existent dans une interface mais échouent ensuite au runtime comme « unsupported ».
Saselang ne retient pas le modèle d'opérations optionnelles présentes dans une interface mais susceptibles d'échouer ensuite comme « unsupported ».
Hiérarchie principale retenue :
Hiérarchie principale :
```text
Iterable<T>
@@ -151,21 +151,84 @@ SettableList<T>
ResizableList<T>
```
`Set<T>` et `Map<K,V>` sont des branches distinctes à préciser.
`Set<T>` et `Map<K,V>` forment des branches sémantiques distinctes.
### 22.4.1 `Iterable<T>` / `Iterator<T>`
### 22.4.1 `Iterable<T>` et `Iterator<T>`
Interfaces Core reconnues par `foreach`.
`foreach` dépend uniquement de `Iterable<T>`.
Elles ne portent pas le préfixe `Op`, car `foreach` est une construction du langage et non un opérateur symbolique.
```text
interface Iterable<T> {
const method iterator() -> Iterator<T>;
}
```
Indexabilité et itérabilité sont indépendantes.
Créer un iterator ne constitue pas une mutation sémantique de la source.
### 22.4.2 `Collection<T>`
`Iterator<T>` représente une itération particulière et possède un état de progression mutable :
```text
interface Iterator<T> {
method next() -> Option<T>;
}
```
`Some(value)` fournit l'élément suivant ; `None` marque la fin normale de l'itération.
Saselang n'impose pas le couple `hasNext()` / `next()`. `Option<T>` rend l'état de fin explicite dans une seule opération.
`Iterator<T>` n'étend pas `Iterable<T>` par défaut. Une source capable de créer des itérations et une itération déjà en cours sont deux capacités différentes, même si certains types concrets peuvent éventuellement fournir les deux.
Pour les collections ordinaires non concurrentes, une mutation structurelle invalide par défaut les iterators actifs lorsque le type concret ne garantit pas explicitement une autre politique.
```text
insert / remove / clear / append / changement structurel
-> peut invalider l'iterator
utilisation ultérieure d'un iterator invalidé
-> IteratorInvalidatedFault
```
Le simple remplacement d'une valeur existante n'est pas automatiquement une mutation structurelle. Le type concret documente sa politique exacte.
Les collections concurrentes ou spécialisées peuvent fournir une autre politique (`snapshot`, stabilité, weak consistency, etc.) ; elle doit être explicite.
### 22.4.2 `View<T>`
`View<T>` représente une vue légère sur une source existante :
```text
interface View<T> extends Iterable<T> {
const method count() -> uint64;
const method isEmpty() -> bool;
}
```
`View<T>` n'étend pas `Collection<T>`.
Le contrat général ne contient pas `contains()`. Une classe ou une interface plus spécialisée peut l'ajouter si elle en a réellement besoin.
Une `View<T>` :
```text
n'impose aucune copie des éléments
n'impose aucun stockage indépendant
n'impose aucune contiguïté
ne possède pas nécessairement les données qu'elle expose
ne peut jamais augmenter les permissions const de sa source
```
Par défaut, une vue est **vivante**, pas un snapshot : une nouvelle itération peut observer les modifications ultérieures de la source selon le contrat du type concret.
Le runtime/compilateur garantit que le stockage ou l'état source nécessaire reste valide aussi longtemps que la vue l'exige, sans syntaxe de lifetime utilisateur.
Le comportement d'un iterator déjà créé avant une modification reste régi par la politique d'invalidation/stabilité du type concret.
### 22.4.3 `Collection<T>`
`Collection<T>` étend `Iterable<T>` et représente une collection finie d'éléments.
Contrat minimal retenu :
Contrat minimal :
```text
count() -> uint64
@@ -175,7 +238,7 @@ contains(const T value) -> bool
`count()` exprime le nombre d'éléments au sens général de collection.
### 22.4.3 `List<T>`
### 22.4.4 `List<T>`
`List<T>` étend `Collection<T>` et `OpIndex<uint64,T>`.
@@ -193,33 +256,39 @@ Pour une `List<T>` :
count() == length()
```
Les deux noms sont néanmoins conservés parce qu'ils expriment des concepts différents : cardinalité générale de collection et longueur d'une séquence indexable.
Les deux noms restent distincts parce qu'ils expriment la cardinalité générale d'une collection et la longueur d'une séquence indexable.
`List<T>` ne garantit ni remplacement d'un élément, ni redimensionnement, ni complexité algorithmique particulière de l'accès indexé.
`List<T>` ne garantit ni remplacement, ni redimensionnement, ni complexité algorithmique particulière de l'accès indexé.
### 22.4.4 `SettableList<T>`
### 22.4.5 `SettableList<T>`
`SettableList<T>` étend `List<T>` et `OpIndexMut<uint64,T>`.
Elle garantit le remplacement d'un élément existant sans modification de la longueur.
Elle garantit le remplacement d'un élément existant sans modification de longueur :
```text
list[index] = value;
```
ne signifie jamais `append` lorsque `index == length()`.
`index` doit désigner une case existante ; l'affectation ne signifie jamais `append`.
### 22.4.5 `ResizableList<T>`
### 22.4.6 `ResizableList<T>`
`ResizableList<T>` étend `SettableList<T>`.
`ResizableList<T>` étend `SettableList<T>` et garantit des opérations structurelles capables de modifier la longueur.
Elle garantit des opérations structurelles capables de modifier la longueur, par exemple ajout, insertion et suppression.
Les signatures exactes seront figées avec `Vector<T>`.
Les signatures exactes seront figées lors de la définition du type concret redimensionnable.
Un `resize(newLength)` sans information d'initialisation n'est pas retenu implicitement : agrandir une collection doit définir comment les nouveaux éléments sont construits.
Un `resize(newLength)` sans information d'initialisation n'est pas retenu implicitement : agrandir une collection doit toujours définir comment les nouveaux éléments sont construits.
Lorsqu'il existe, `clear()` suit la convention :
### 22.4.6 Capacité du type et permission `const`
```text
clear() -> uint64
```
et retourne le nombre d'éléments effectivement supprimés.
### 22.4.7 Capacité du type et permission `const`
La capacité intrinsèque du type et la permission d'un accès sont deux dimensions distinctes.
@@ -230,9 +299,9 @@ const SettableList<User> readonly = users;
Le type sait remplacer des éléments, mais l'accès `readonly` ne peut pas utiliser cette capacité.
La propagation générale de `const` reste applicable aux éléments obtenus via cet accès.
La même règle s'applique à `Map`, `Set`, `View` et aux éléments obtenus à travers ces accès : une projection ne peut jamais augmenter les droits reçus de sa source.
### 22.4.7 Classification initiale
### 22.4.8 Classification initiale des séquences
```text
StaticArray<T,N>
@@ -258,9 +327,271 @@ Vector<T>
`Vector<T>` reste à définir précisément.
Un type persistant/immutable par nature n'a aucune obligation d'implémenter `List<T>`. Par exemple, un futur `PersistentList<T>` peut implémenter uniquement `Collection<T>` et fournir ses propres opérations si cela correspond mieux à sa sémantique.
Un type persistant/immutable par nature n'a aucune obligation d'implémenter `List<T>` s'il ne garantit pas sa sémantique.
Une interface Saselang n'est jamais implémentée uniquement parce qu'un type ressemble conceptuellement à une autre famille de types.
### 22.4.9 `Set<T>` et `ResizableSet<T>`
`Set<T>` étend `Collection<T>`.
Il garantit :
```text
unicité des éléments
aucun index ordinal
aucun ordre d'itération général garanti
```
La capacité structurelle est séparée :
```text
interface ResizableSet<T> extends Set<T> {
method add(T value) -> bool;
method remove(const T value) -> bool;
method clear() -> uint64;
}
```
Sémantique :
```text
add(value)
true -> élément ajouté
false -> élément déjà présent, set inchangé
remove(value)
true -> élément supprimé
false -> élément absent
clear()
-> nombre d'éléments effectivement supprimés
```
Il n'existe pas de niveau `SettableSet<T>` : remplacer un élément d'un set équivaut conceptuellement à une modification structurelle de son ensemble de valeurs.
### 22.4.10 `Map<K,V>`, `SettableMap<K,V>` et `ResizableMap<K,V>`
`Map<K,V>` n'étend pas `Collection<T>` et n'implémente pas directement `Iterable<...>`. Une map possède trois projections naturelles différentes : clés, valeurs et entrées ; aucune ne doit être choisie implicitement comme itération « par défaut ».
Contrat de lecture :
```text
interface Map<K,V> extends OpIndex<K,V> {
const method count() -> uint64;
const method isEmpty() -> bool;
const method containsKey(const K key) -> bool;
const method get(const K key) -> Option<V>;
const method keys() -> View<K>;
const method values() -> View<V>;
const method entries() -> View<MapEntry<K,V>>;
}
```
Deux intentions sont séparées :
```text
map[key] -> V
accès strict
la clé doit exister
absence dynamique -> KeyNotFoundFault
map::get(key) -> Option<V>
accès conditionnel
absence normale -> None
```
`SettableMap<K,V>` étend `Map<K,V>` et `OpIndexMut<K,V>`.
```text
map[key] = value;
```
remplace uniquement la valeur d'une clé existante. Cette syntaxe n'insère jamais implicitement une nouvelle clé. Une clé absente produit `KeyNotFoundFault`.
`ResizableMap<K,V>` étend `SettableMap<K,V>` et ajoute les changements structurels :
```text
insert(K key, V value) -> Void
faults DuplicateKeyFault
remove(const K key) -> Void
faults KeyNotFoundFault
clear() -> uint64
```
`insert` affirme que la clé est nouvelle ; `remove` affirme qu'elle existe. Leurs violations dynamiques sont des `Fault` unchecked et capturables.
Le Core ne fournit pas mécaniquement `tryInsert` / `tryRemove` ayant pour seule fonction de dupliquer ces opérations dans `Result` ou `bool`. Une variante conditionnelle ne sera ajoutée que si elle porte une sémantique réellement utile distincte.
Il n'existe pas de `put()` implicite « insert ou replace » tant qu'un besoin concret ne justifie pas cette troisième intention.
### 22.4.11 `MapEntry<K,V>`
`MapEntry<K,V>` représente une paire clé/valeur observée lors d'une projection `entries()`.
Conceptuellement :
```text
struct MapEntry<K,V> {
const method key() -> K;
const method value() -> V;
}
```
`MapEntry` n'est pas un proxy mutable vers un bucket interne de la map et n'expose pas de `setValue()` implicite.
La mutation d'une map reste explicite via :
```text
map[key] = value;
```
La sémantique de copie/référence de `K` et `V` suit les règles normales de leurs types.
### 22.4.12 Ordre : `Ordering`, `Comparable<T>` et `Comparator<T>`
L'ordre total applicatif utilise :
```text
enum Ordering {
Less,
Equal,
Greater
}
```
`Comparable<T>` exprime l'ordre naturel ou principal du type dans son domaine :
```text
interface Comparable<T> {
const method compareTo(const T other) -> Ordering;
}
```
Un type peut tout à fait implémenter `Comparable<T>` tout en supportant plusieurs ordres alternatifs via des comparators. Par exemple, un `User` d'un jeu peut avoir un classement principal naturel et rester comparable autrement par nom, niveau ou date.
`Comparator<T>` exprime un ordre externe/alternatif :
```text
interface Comparator<T> {
const method compare(const T left, const T right) -> Ordering;
}
```
Règle de sélection :
```text
Comparator explicitement fourni
-> utilisé exclusivement
aucun Comparator fourni
-> Comparable<T> requis
```
Aucun mélange/fallback entre les deux n'est effectué pendant une même opération ou dans une même collection ordonnée.
`Ordering::Equal` signifie équivalence selon cette relation d'ordre. Il n'implique pas nécessairement `left == right`.
Les implémentations de `Comparable` et `Comparator` doivent respecter cohérence, symétrie d'ordre et transitivité. Le compilateur n'est pas tenu de prouver ces propriétés générales.
### 22.4.13 `SortedSet<T>` et `SortedMap<K,V>`
`SortedSet<T>` étend `Set<T>` et garantit un ordre total stable selon le comparator actif :
```text
interface SortedSet<T> extends Set<T> {
const method comparator() -> Option<Comparator<T>>;
const method first() -> Option<T>;
const method last() -> Option<T>;
}
```
`None` pour `comparator()` signifie que l'ordre naturel `Comparable<T>` est utilisé. `Some(comparator)` expose l'ordre externe choisi pour cette instance.
`SortedMap<K,V>` étend `Map<K,V>` et ordonne les entrées par clé :
```text
interface SortedMap<K,V> extends Map<K,V> {
const method comparator() -> Option<Comparator<K>>;
const method firstKey() -> Option<K>;
const method lastKey() -> Option<K>;
}
```
Pour une `SortedMap`, les vues `keys()`, `values()` et `entries()` parcourent les données dans l'ordre des clés.
Les opérations de bornes/ranges (`floor`, `ceiling`, `lower`, `higher` ou noms définitifs) seront fermées séparément afin de ne pas introduire de noms ambigus par simple imitation d'une autre plateforme.
### 22.4.14 `TreeSet<T>` et `TreeMap<K,V>`
Les types standard ordonnés généraux sont nommés :
```text
TreeSet<T>
TreeMap<K,V>
```
Le nom n'impose pas une structure arborescente précise au niveau ABI/implémentation tant que le contrat observable reste respecté.
Un futur `BTreeMap<K,V>` peut exister comme implémentation explicitement fondée sur un B-tree ; il ne remplace pas le nom général `TreeMap`.
Comme Saselang n'autorise qu'un `construct` par classe, les deux modes de création passent par des factories de classe distinctes :
```text
TreeSet<T>::natural()
requiert T implements Comparable<T>
TreeSet<T>::withComparator(Comparator<T> comparator)
n'exige pas Comparable<T>
TreeMap<K,V>::natural()
requiert K implements Comparable<K>
TreeMap<K,V>::withComparator(Comparator<K> comparator)
n'exige pas Comparable<K>
```
Les contraintes appartiennent aux factories concernées et non nécessairement au type générique entier.
### 22.4.15 Contraintes des implémentations concrètes
Les interfaces abstraites `Set<T>` et `Map<K,V>` n'imposent pas une stratégie de stockage particulière.
Ainsi :
```text
HashSet<T> / HashMap<K,V>
peuvent exiger des capacités de hash/égalité
TreeSet<T> / TreeMap<K,V>
utilisent Comparable ou Comparator
```
`Hashable`, l'égalité et leurs contrats exacts seront fermés dans le bloc dédié. Ils ne sont pas imposés à `Set<T>` ou `Map<K,V>` eux-mêmes.
### 22.4.16 Collections concurrentes
Les garanties concurrentes sont orthogonales aux capacités structurelles et relèvent du SDK.
Une future :
```text
ConcurrentMap<K,V>
```
exprime des garanties de concurrence/atomicité et ne remplace pas `ResizableMap<K,V>`.
Un type concret peut par exemple implémenter les deux :
```text
ConcurrentHashMap<K,V>
implements ResizableMap<K,V>, ConcurrentMap<K,V>
```
Le SDK n'introduit pas une variante `ConcurrentX` pour chaque type uniquement par symétrie. Les interfaces concurrentes ne sont ajoutées que lorsqu'un contrat atomique/concurrent concret existe.
Une opération composée n'est pas atomique simplement parce que chaque appel individuel est thread-safe. Les futures opérations atomiques (`putIfAbsent`, comparaison/remplacement, etc.) seront spécifiées avec le modèle de concurrence.
## 22.5 `Range<T>` — V1 REQUIS — FIGÉ EN PRINCIPE
@@ -308,7 +639,7 @@ valeur finie autorisée
Les bornes sont évaluées de gauche à droite, exactement une fois chacune, avant la construction du range.
Une borne statiquement prouvée invalide provoque une erreur de compilation. Une borne calculée dynamiquement mais invalide selon le contrat de `Range<T>` provoque un runtime fault lors de la construction directe. Une API Core explicite retournant `Result` pourra être fournie lorsqu'une validation récupérable est souhaitée.
Une borne statiquement prouvée invalide provoque une erreur de compilation. Une borne calculée dynamiquement mais invalide selon le contrat de `Range<T>` provoque un `Fault` runtime lors de la construction directe. Le nom concret du fault sera fixé avec l'API Core ; aucune variante `try... -> Result` parallèle n'est créée automatiquement pour la même validation.
`lower > upper` ne constitue pas une erreur : le résultat est un range vide.
@@ -392,7 +723,7 @@ RangeStep<Date,Duration>
et de refuser des couples qui introduiraient une perte ou n'auraient pas de sens. Par exemple, un range `float16` peut recevoir seulement les types de pas explicitement supportés sans imposer qu'un `float32` plus large soit accepté.
Le pas exprime une magnitude de progression, pas une direction. Pour les types numériques Core, il doit être strictement supérieur à zéro. Un pas statiquement nul ou négatif est une erreur de compilation ; une valeur dynamique invalide provoque un runtime fault lors de la construction directe de la progression. Une API explicite en `Result` pourra exister pour une validation récupérable.
Le pas exprime une magnitude de progression, pas une direction. Pour les types numériques Core, il doit être strictement supérieur à zéro. Un pas statiquement nul ou négatif est une erreur de compilation ; une valeur dynamique invalide provoque un `Fault` runtime lors de la construction directe de la progression. Aucune variante `try... -> Result` n'est ajoutée uniquement pour dupliquer ce contrôle.
Pour les types utilisateur, la validité du pas est définie par le contrat Range correspondant et n'est pas réduite artificiellement à une comparaison numérique avec zéro.