Le langage 4D
Chaque entrée de cette page vient d'un incident réel. Elles ont un point commun : 4D ne vous prévient pas. L'erreur surgit trois niveaux plus loin, ou la valeur renvoyée a l'air plausible.
Null n'est pas vide, et Null n'est pas undefined
Num(Null) lève une erreur : « Les arguments sont incompatibles ». Une entité ORDA fraîchement créée a ses attributs numériques à Null, pas à 0. Un attribut calculé qui fait Num(This.amount) rend l'entité illisible et impossible à supprimer : la couche d'historique relit la version précédente au .store() et tombe sur la même erreur. Initialisez chaque numérique avant la première sauvegarde.
String(Null) renvoie le texte "null". String(x) # "" est donc vrai pour un champ vide, et le garde-fou que vous avez écrit fait l'inverse de ce que vous vouliez. Testez # Null d'abord.
Une propriété absente vaut undefined, pas Null. Un garde-fou # Null ne protège de rien face à une clé qui n'a jamais été posée. Testez ce que vous attendez réellement (Value type, ou la présence de la clé).
Une date Null comparée à un littéral lève une erreur. If (X.myDate # !00-00-00!) sur un attribut date jamais rempli donne « Les arguments de cette opération sont incompatibles ». Passez par une variable typée Date. Constaté sous la forme d'une erreur 500 sur un call-action après l'écriture de l'enregistrement : les données étaient sauvegardées, et la redirection ne s'est jamais faite.
Un champ booléen sans never_null casse un If. Même famille, même erreur 500.
Les opérateurs
&& et || ne court-circuitent pas, et la priorité s'applique de gauche à droite. Dans A || B && C, 4D évalue dans l'ordre de lecture. Mettez des parenthèses, et ne comptez jamais sur la partie gauche pour protéger la partie droite : (X # Null) && (X.field = 1) évalue quand même X.field.
Un ternaire passé en argument d'appel donne « Une fonction est attendue ». Affectez-le d'abord à une variable.
Les collections
String() ou Replace string() sur une collection lève « Les arguments sont incompatibles », ce qui se manifeste par une erreur 500, un gabarit mort ou un champ disparu. Testez Value type = Is collection avant toute conversion. Notez que el.value sur un select multiple ne renvoie que la première option : c'est ainsi qu'une collection se retrouve là où une chaîne était attendue.
union() n'existe pas. Utilisez concat() (nouvelle collection) ou combine() (sur place). Appeler union() fait échouer le bloc appelant.
collection.query() ne fonctionne que sur des objets, pas sur des valeurs scalaires.
Variables typées et objets partagés
Une variable typée est contrôlée avant votre test de type. Une variable de boucle ou un paramètre déclaré lève une erreur à l'affectation, avant le Case of censé détecter le type. Recevez la valeur sans type puis testez-la, ou ne la typez pas.
Remplissez un objet partagé en dehors du Use. Construire le contenu à l'intérieur provoque une erreur 500 : construisez-le, puis n'utilisez Use que pour l'affectation. OB Copy(…; ck shared) est la forme fiable.
For each sur un objet partagé n'est pas autorisé dans les contextes où BWEB fait son rendu : construisez d'abord une copie ordinaire.
Fichiers et dossiers
File(Application file) renvoie Null sans fk platform path, et un Try l'avale : le fichier attendu n'apparaît tout simplement jamais.
.parent lève une erreur au-dessus d'un dossier système de 4D. La fonction renvoie Null et l'erreur surgit trois niveaux plus haut, loin de sa cause. Pour les opérations git, ne remontez pas du tout : git trouve sa racine tout seul.
File.name retire l'extension. Utilisez fullName quand vous en avez besoin.
Nombres et dates venus du web
Num() casse les décimaux venus d'un formulaire : utilisez BSPK_STRING_TO_REAL.
Une date stockée en texte ISO dans APP_PARAMETERS revient sous forme de Date 4D depuis Storage. Un For each typé Texte lève alors l'erreur 54, et JSON Stringify ment sur ce qu'il y a dedans.
Ne réanalysez jamais une date par Substring à position fixe.
Celui qui cache tous les autres
Une erreur de syntaxe dans une seule fonction rend toute la classe inchargeable. Toutes les autres fonctions de la classe disparaissent, bspk.log ne dit rien, et le symptôme est une erreur 500 générique — ou une listbox qui s'affiche vide. Seule la fenêtre du compilateur 4D nomme l'erreur.
Réflexe : quand plusieurs choses sans rapport cassent en même temps, soupçonnez une classe cassée avant de soupçonner votre modification.
Voir aussi
- 4D dans BWEB — les pièges propres au rendu et au code du composant
- Les événements et le POST — là où plusieurs de ces pièges se manifestent par « il ne se passe rien »

