HeadlinesBriefing HeadlinesBriefing 12 languages

C++26 Contracts: Introduction to Preconditions and Postconditions

Hacker News ·

🇬🇧 English

In the article on Standard Library hardening, we saw that many library requirements are expressed as "contracts." This post explores contracts in C++26 and how they can be applied to our own code.

The discussion starts with a simple example: a function that returns a value from a std::vector at a given index. Traditionally, the requirement that the index be valid is enforced with assert inside the function body. This approach has drawbacks. The requirement lives in the implementation, so someone reading only the declaration sees a vector and an index without the relationship between them. Assertions are also controlled only by NDEBUG, which removes the check entirely when defined.

C++26 contracts, introduced through P2900, move the requirement into the function signature with a pre(...) clause placed after the parameter list. This precondition states a condition expected to hold on entry to the function. The same requirement can also appear on the declaration, making it visible to anyone reading the API. Contracts offer several evaluation semantics, including ignoring a check, reporting a violation and continuing, or terminating the program, with the compiler implementation determining which are available and how they are selected.

Contracts also distinguish between what the caller must provide and what the function promises to return. Postconditions, introduced with post, express those promises without requiring manual checks before each return statement. This makes contracts useful for documenting APIs even when runtime checking is disabled.

The article concludes with a complete precondition example and covers further topics such as postconditions, the placement of contracts on declarations and definitions, compiler options, and details that can surprise developers.

View original article →


🇸🇦 العربية

عقود C++26: مقدمة عن الشروط المسبقة والشروط اللاحقة

في المقال المتعلق بتقوية المكتبة القياسية، رأينا أن كثيرًا من متطلبات المكتبة يُعبَّر عنها بوصفها "عقودًا". يستكشف هذا المنشور العقود في C++26 وكيفية تطبيقها على شيفرتنا الخاصة.

يبدأ النقاش بمثال بسيط: دالة تُرجع قيمة من std::vector عند فهرس معين. تقليديًا، يُفرض شرط صلاحية الفهرس باستخدام assert داخل جسم الدالة. لهذا النهج عيوب. يعيش الشرط في التنفيذ، لذا فإن من يقرأ التصريح وحده يرى vector وفهرسًا دون العلاقة بينهما. كما أن التأكيدات تتحكم بها NDEBUG فقط، التي تزيل الفحص تمامًا عند تعريفها.

تنقل عقود C++26، التي قُدِّمت عبر P2900، الشرط إلى توقيع الدالة باستخدام بند pre(...) الموضوع بعد قائمة المعاملات. يذكر هذا الشرط المسبق شرطًا يُتوقع تحققه عند دخول الدالة. ويمكن أن يظهر المتطلب نفسه في التصريح، فيصبح مرئيًا لكل من يقرأ الواجهة البرمجية. تقدم العقود عدة دلالات للتقييم، منها تجاهل الفحص، أو الإبلاغ عن الانتهاك والاستمرار، أو إنهاء البرنامج، ويحدد تنفيذ المترجم الخيارات المتاحة وكيفية اختيارها.

تميّز العقود أيضًا بين ما يجب على المستدعي توفيره وما تَعِد الدالة بإرجاعه. وتعبّر الشروط اللاحقة، المقدَّمة بالبند post، عن هذه الوعود دون الحاجة إلى فحوص يدوية قبل كل عبارة return. وهذا يجعل العقود مفيدة في توثيق الواجهات البرمجية حتى عند تعطيل الفحص أثناء التشغيل.

يختتم المقال بمثال كامل للشرط المسبق، ويغطي موضوعات إضافية مثل الشروط اللاحقة، وموضع العقود في التصريحات والتعريفات، وخيارات المترجم، وتفاصيل قد تفاجئ المطورين.

ما الفرق بين عقود C++26 وassert؟

تضع العقود الشروط المسبقة واللاحقة مباشرة في تصريح الدالة، فتصبح المتطلبات مرئية في الواجهة البرمجية. كما تقدم عدة دلالات للتقييم، مثل تجاهل الفحص، أو الإبلاغ عن الانتهاك والاستمرار، أو الإنهاء، بدلًا من التحكم بها عبر NDEBUG فقط.

العربية version →


🇧🇩 বাংলা

C++26 কনট্র্যাক্ট: প্রিকন্ডিশন ও পোস্টকন্ডিশনের পরিচিতি

স্ট্যান্ডার্ড লাইব্রেরি হার্ডেনিং সংক্রান্ত নিবন্ধে আমরা দেখেছি যে লাইব্রেরির অনেক প্রয়োজনীয়তা "কনট্র্যাক্ট" হিসেবে প্রকাশ করা হয়। এই পোস্টে C++26-এর কনট্র্যাক্ট নিয়ে আলোচনা করা হয়েছে এবং কীভাবে সেগুলো আমাদের নিজস্ব কোডে প্রয়োগ করা যায় তা দেখানো হয়েছে।

আলোচনা একটি সহজ উদাহরণ দিয়ে শুরু হয়: একটি ফাংশন যা নির্দিষ্ট ইন্ডেক্সে একটি std::vector থেকে একটি মান ফেরত দেয়। ঐতিহ্যগতভাবে, ইন্ডেক্সটি বৈধ হওয়ার প্রয়োজনীয়তা ফাংশনের বডির ভেতরে assert দিয়ে কার্যকর করা হয়। এই পদ্ধতির কিছু সীমাবদ্ধতা আছে। প্রয়োজনীয়তাটি ইমপ্লিমেন্টেশনের ভেতরে থাকে, তাই শুধু ডিক্লারেশন পড়া কেউ একটি vector ও একটি ইন্ডেক্স দেখে, কিন্তু তাদের মধ্যকার সম্পর্ক দেখে না। অ্যাসারশনগুলো শুধু NDEBUG দিয়ে নিয়ন্ত্রিত হয়, এবং সেটি সংজ্ঞায়িত থাকলে পরীক্ষাটি সম্পূর্ণ বাদ পড়ে যায়।

P2900-এর মাধ্যমে প্রবর্তিত C++26 কনট্র্যাক্ট প্রয়োজনীয়তাটিকে ফাংশন সিগনেচারে নিয়ে যায়, প্যারামিটার তালিকার পরে বসানো pre(...) ক্লজের মাধ্যমে। এই প্রিকন্ডিশন বলে দেয় ফাংশনে প্রবেশের সময় কোন শর্তটি সত্য হওয়ার আশা করা হচ্ছে। একই প্রয়োজনীয়তা ডিক্লারেশনেও উপস্থিত থাকতে পারে, যাতে API পড়া যে কেউ তা দেখতে পায়। কনট্র্যাক্ট একাধিক মূল্যায়ন সিমান্টিক্স দেয়, যার মধ্যে পরীক্ষাটি উপেক্ষা করা, লঙ্ঘন রিপোর্ট করে এগিয়ে যাওয়া, বা প্রোগ্রাম বন্ধ করে দেওয়া অন্তর্ভুক্ত। কোনগুলো উপলব্ধ এবং কীভাবে নির্বাচন করা হবে তা কম্পাইলার ইমপ্লিমেন্টেশন নির্ধারণ করে।

কনট্র্যাক্ট আরও আলাদা করে দেখায় কলারকে কী সরবরাহ করতে হবে এবং ফাংশন কী ফেরত দেওয়ার প্রতিশ্রুতি দেয়। post দিয়ে প্রবর্তিত পোস্টকন্ডিশন প্রতিটি return স্টেটমেন্টের আগে ম্যানুয়াল পরীক্ষার প্রয়োজন ছাড়াই সেই প্রতিশ্রুতিগুলো প্রকাশ করে। ফলে রানটাইম পরীক্ষা বন্ধ থাকলেও কনট্র্যাক্ট API ডকুমেন্ট করতে কাজে আসে।

নিবন্ধটি একটি সম্পূর্ণ প্রিকন্ডিশন উদাহরণ দিয়ে শেষ হয় এবং পোস্টকন্ডিশন, ডিক্লারেশন ও ডেফিনিশনে কনট্র্যাক্টের অবস্থান, কম্পাইলার অপশন, এবং ডেভেলপারদের অবাক করতে পারে এমন বিবরণসহ আরও বিষয় নিয়ে আলোচনা করে।

C++26 কনট্র্যাক্ট কীভাবে assert থেকে আলাদা?

কনট্র্যাক্ট প্রি ও পোস্ট কন্ডিশন সরাসরি ফাংশন ডিক্লারেশনে রাখে, ফলে প্রয়োজনীয়তাগুলো API-তে দৃশ্যমান হয়। এগুলো একাধিক মূল্যায়ন সিমান্টিক্সও দেয়, যেমন পরীক্ষা উপেক্ষা করা, লঙ্ঘন রিপোর্ট করে চালিয়ে যাওয়া, বা বন্ধ করে দেওয়া, শুধু NDEBUG দিয়ে নিয়ন্ত্রিত না হয়ে।

বাংলা version →


🇩🇪 Deutsch

C++26-Contracts: Einführung in Vorbedingungen und Nachbedingungen

Im Artikel zur Härtung der Standardbibliothek haben wir gesehen, dass viele Anforderungen der Bibliothek als "Contracts" formuliert sind. Dieser Beitrag untersucht Contracts in C++26 und wie sie auf den eigenen Code angewendet werden können.

Die Diskussion beginnt mit einem einfachen Beispiel: eine Funktion, die einen Wert aus einem std::vector an einem bestimmten Index zurückgibt. Traditionell wird die Anforderung, dass der Index gültig ist, mit assert im Funktionskörper durchgesetzt. Dieser Ansatz hat Nachteile. Die Anforderung steckt in der Implementierung, sodass jemand, der nur die Deklaration liest, einen vector und einen Index sieht, ohne den Zusammenhang zwischen beiden. Assertions werden außerdem nur über NDEBUG gesteuert, das die Prüfung bei Definition vollständig entfernt.

C++26-Contracts, eingeführt durch P2900, verschieben die Anforderung in die Funktionssignatur, mit einer pre(...)-Klausel nach der Parameterliste. Diese Vorbedingung beschreibt eine Bedingung, die beim Eintritt in die Funktion erwartet wird. Dieselbe Anforderung kann auch in der Deklaration auftauchen und ist damit für jeden sichtbar, der die API liest. Contracts bieten mehrere Auswertungssemantiken, etwa das Ignorieren einer Prüfung, das Melden einer Verletzung mit anschließendem Fortfahren oder das Beenden des Programms. Welche verfügbar sind und wie sie ausgewählt werden, bestimmt die Compiler-Implementierung.

Contracts unterscheiden außerdem zwischen dem, was der Aufrufer bereitstellen muss, und dem, was die Funktion zurückzugeben verspricht. Nachbedingungen, eingeführt mit post, formulieren diese Zusagen, ohne vor jeder return-Anweisung manuelle Prüfungen zu erfordern. Dadurch sind Contracts auch dann zur Dokumentation von APIs nützlich, wenn die Laufzeitprüfung deaktiviert ist.

Der Artikel schließt mit einem vollständigen Beispiel für eine Vorbedingung ab und behandelt weitere Themen wie Nachbedingungen, die Platzierung von Contracts an Deklarationen und Definitionen, Compiler-Optionen sowie Details, die Entwickler überraschen können.

Wie unterscheiden sich C++26-Contracts von assert?

Contracts platzieren Vor- und Nachbedingungen direkt in der Funktionsdeklaration, sodass die Anforderungen in der API sichtbar werden. Sie bieten außerdem mehrere Auswertungssemantiken, etwa das Ignorieren einer Prüfung, das Melden einer Verletzung mit anschließendem Fortfahren oder das Beenden, statt nur über NDEBUG gesteuert zu werden.

Deutsch version →


🇪🇸 Español

Contratos de C++26: introducción a las precondiciones y postcondiciones

En el artículo sobre el endurecimiento de la biblioteca estándar, vimos que muchos requisitos de la biblioteca se expresan como "contratos". Esta publicación explora los contratos en C++26 y cómo pueden aplicarse a nuestro propio código.

La explicación comienza con un ejemplo sencillo: una función que devuelve un valor de un std::vector en un índice dado. Tradicionalmente, el requisito de que el índice sea válido se impone con assert dentro del cuerpo de la función. Este enfoque tiene inconvenientes. El requisito vive en la implementación, por lo que quien lea solo la declaración ve un vector y un índice sin la relación entre ambos. Además, las aserciones solo se controlan mediante NDEBUG, que elimina la comprobación por completo cuando se define.

Los contratos de C++26, introducidos mediante P2900, trasladan el requisito a la firma de la función con una cláusula pre(...) colocada después de la lista de parámetros. Esta precondición establece una condición que se espera que se cumpla al entrar en la función. El mismo requisito también puede aparecer en la declaración, haciéndolo visible para cualquiera que lea la API. Los contratos ofrecen varias semánticas de evaluación, como ignorar una comprobación, informar de una violación y continuar, o terminar el programa, determinando la implementación del compilador cuáles están disponibles y cómo se seleccionan.

Los contratos también distinguen entre lo que el llamador debe proporcionar y lo que la función promete devolver. Las postcondiciones, introducidas con post, expresan esas promesas sin requerir comprobaciones manuales antes de cada sentencia return. Esto hace que los contratos sean útiles para documentar APIs incluso cuando la comprobación en tiempo de ejecución está desactivada.

El artículo concluye con un ejemplo completo de precondición y abarca temas adicionales como las postcondiciones, la ubicación de los contratos en declaraciones y definiciones, las opciones del compilador y detalles que pueden sorprender a los desarrolladores.

¿En qué se diferencian los contratos de C++26 de assert?

Los contratos colocan las precondiciones y postcondiciones directamente en la declaración de la función, haciendo visibles los requisitos en la API. También ofrecen varias semánticas de evaluación, como ignorar una comprobación, informar de una violación y continuar, o terminar, en lugar de estar controlados únicamente por NDEBUG.

Español version →


🇫🇷 Français

Contrats C++26 : introduction aux préconditions et postconditions

Dans l'article sur le renforcement de la bibliothèque standard, nous avons vu que de nombreuses exigences de la bibliothèque sont exprimées sous forme de « contrats ». Cet article explore les contrats en C++26 et la manière de les appliquer à notre propre code.

La discussion commence par un exemple simple : une fonction qui renvoie une valeur d'un std::vector à un indice donné. Traditionnellement, l'exigence de validité de l'indice est imposée par assert dans le corps de la fonction. Cette approche présente des inconvénients. L'exigence se trouve dans l'implémentation, si bien que quelqu'un qui ne lit que la déclaration voit un vector et un indice, sans le lien entre les deux. Les assertions ne sont par ailleurs contrôlées que par NDEBUG, qui supprime entièrement la vérification lorsqu'elle est définie.

Les contrats de C++26, introduits par P2900, déplacent l'exigence dans la signature de la fonction, grâce à une clause pre(...) placée après la liste des paramètres. Cette précondition énonce une condition attendue à l'entrée de la fonction. La même exigence peut également figurer dans la déclaration, la rendant visible pour quiconque lit l'API. Les contrats offrent plusieurs sémantiques d'évaluation, notamment ignorer une vérification, signaler une violation puis poursuivre, ou terminer le programme ; c'est l'implémentation du compilateur qui détermine lesquelles sont disponibles et comment les sélectionner.

Les contrats distinguent aussi ce que l'appelant doit fournir de ce que la fonction promet de renvoyer. Les postconditions, introduites avec post, expriment ces promesses sans nécessiter de vérifications manuelles avant chaque instruction return. Les contrats sont ainsi utiles pour documenter les API, même lorsque la vérification à l'exécution est désactivée.

L'article se termine par un exemple complet de précondition et aborde d'autres sujets, comme les postconditions, le placement des contrats sur les déclarations et les définitions, les options du compilateur et des détails susceptibles de surprendre les développeurs.

En quoi les contrats C++26 diffèrent-ils de assert ?

Les contrats placent les préconditions et postconditions directement dans la déclaration de la fonction, rendant les exigences visibles dans l'API. Ils offrent également plusieurs sémantiques d'évaluation, comme ignorer une vérification, signaler une violation et poursuivre, ou terminer, au lieu d'être contrôlés uniquement par NDEBUG.

Français version →


🇮🇳 हिन्दी

C++26 कॉन्ट्रैक्ट्स: प्रीकंडीशन और पोस्टकंडीशन का परिचय

स्टैंडर्ड लाइब्रेरी हार्डनिंग पर लिखे लेख में हमने देखा कि कई लाइब्रेरी आवश्यकताएँ "कॉन्ट्रैक्ट्स" के रूप में व्यक्त की जाती हैं। यह पोस्ट C++26 में कॉन्ट्रैक्ट्स की पड़ताल करती है और बताती है कि उन्हें हमारे अपने कोड पर कैसे लागू किया जा सकता है।

चर्चा एक सरल उदाहरण से शुरू होती है: एक फ़ंक्शन जो दिए गए इंडेक्स पर std::vector से एक मान लौटाता है। पारंपरिक रूप से, इंडेक्स मान्य होने की आवश्यकता फ़ंक्शन बॉडी के भीतर assert द्वारा लागू की जाती है। इस तरीके की कुछ कमियाँ हैं। आवश्यकता इम्प्लीमेंटेशन में रहती है, इसलिए केवल डिक्लेरेशन पढ़ने वाला व्यक्ति एक vector और एक इंडेक्स देखता है, पर दोनों के बीच का संबंध नहीं देख पाता। असर्शन केवल NDEBUG से नियंत्रित होते हैं, और इसे परिभाषित करने पर जाँच पूरी तरह हटा दी जाती है।

C++26 कॉन्ट्रैक्ट्स, जो P2900 के माध्यम से प्रस्तुत हुए हैं, आवश्यकता को फ़ंक्शन सिग्नेचर में ले जाते हैं, पैरामीटर सूची के बाद रखे गए pre(...) क्लॉज़ के रूप में। यह प्रीकंडीशन बताती है कि फ़ंक्शन में प्रवेश करते समय कौन सी शर्त सत्य होने की अपेक्षा है। वही आवश्यकता डिक्लेरेशन पर भी दिखाई जा सकती है, जिससे API पढ़ने वाले हर व्यक्ति को वह दिखे। कॉन्ट्रैक्ट्स कई मूल्यांकन सेमांटिक्स देते हैं, जिनमें जाँच को अनदेखा करना, उल्लंघन की रिपोर्ट करके आगे बढ़ना, या प्रोग्राम को समाप्त करना शामिल है। कौन से विकल्प उपलब्ध हैं और उन्हें कैसे चुना जाता है, यह कंपाइलर इम्प्लीमेंटेशन तय करता है।

कॉन्ट्रैक्ट्स इस बात में भी अंतर करते हैं कि कॉलर को क्या देना होगा और फ़ंक्शन क्या लौटाने का वादा करता है। post के साथ प्रस्तुत पोस्टकंडीशन ये वादे व्यक्त करते हैं, बिना हर return स्टेटमेंट से पहले मैन्युअल जाँच की ज़रूरत के। इसलिए रनटाइम जाँच बंद होने पर भी कॉन्ट्रैक्ट्स API का दस्तावेज़ीकरण करने में उपयोगी रहते हैं।

लेख एक पूर्ण प्रीकंडीशन उदाहरण के साथ समाप्त होता है और पोस्टकंडीशन, डिक्लेरेशन और डेफ़िनिशन पर कॉन्ट्रैक्ट्स की जगह, कंपाइलर विकल्प, तथा ऐसे विवरण जो डेवलपर्स को चौंका सकते हैं, जैसे विषयों को भी कवर करता है।

C++26 कॉन्ट्रैक्ट्स assert से कैसे अलग हैं?

कॉन्ट्रैक्ट्स प्री और पोस्ट कंडीशन को सीधे फ़ंक्शन डिक्लेरेशन में रखते हैं, जिससे आवश्यकताएँ API में दिखती हैं। वे कई मूल्यांकन सेमांटिक्स भी देते हैं, जैसे जाँच को अनदेखा करना, उल्लंघन की रिपोर्ट करके आगे बढ़ना, या समाप्त करना, केवल NDEBUG द्वारा नियंत्रित होने के बजाय।

हिन्दी version →


🇮🇩 Bahasa Indonesia

Kontrak C++26: Pengantar Prakondisi dan Pascakondisi

Dalam artikel tentang penguatan Standard Library, kita telah melihat bahwa banyak persyaratan library dinyatakan sebagai "kontrak". Postingan ini membahas kontrak di C++26 dan bagaimana kontrak dapat diterapkan pada kode kita sendiri.

Pembahasan dimulai dengan contoh sederhana: sebuah fungsi yang mengembalikan nilai dari std::vector pada indeks tertentu. Secara tradisional, persyaratan bahwa indeks valid ditegakkan dengan assert di dalam badan fungsi. Pendekatan ini memiliki kelemahan. Persyaratan berada di implementasi, sehingga seseorang yang hanya membaca deklarasi melihat sebuah vector dan indeks tanpa hubungan di antara keduanya. Assertion juga hanya dikendalikan oleh NDEBUG, yang menghapus pemeriksaan sepenuhnya ketika didefinisikan.

Kontrak C++26, yang diperkenalkan melalui P2900, memindahkan persyaratan ke dalam signature fungsi dengan klausa pre(...) yang ditempatkan setelah daftar parameter. Prakondisi ini menyatakan kondisi yang diharapkan berlaku saat masuk ke fungsi. Persyaratan yang sama juga dapat muncul pada deklarasi, sehingga terlihat oleh siapa pun yang membaca API. Kontrak menawarkan beberapa semantik evaluasi, termasuk mengabaikan pemeriksaan, melaporkan pelanggaran lalu melanjutkan, atau menghentikan program, dengan implementasi compiler yang menentukan opsi mana yang tersedia dan bagaimana cara memilihnya.

Kontrak juga membedakan antara apa yang harus disediakan pemanggil dan apa yang dijanjikan fungsi untuk dikembalikan. Pascakondisi, yang diperkenalkan dengan post, menyatakan janji-janji tersebut tanpa memerlukan pemeriksaan manual sebelum setiap pernyataan return. Hal ini membuat kontrak berguna untuk mendokumentasikan API bahkan ketika pemeriksaan saat runtime dinonaktifkan.

Artikel ini diakhiri dengan contoh prakondisi yang lengkap dan membahas topik lanjutan seperti pascakondisi, penempatan kontrak pada deklarasi dan definisi, opsi compiler, serta detail yang dapat mengejutkan pengembang.

Apa perbedaan kontrak C++26 dengan assert?

Kontrak menempatkan prakondisi dan pascakondisi langsung pada deklarasi fungsi, sehingga persyaratan terlihat di API. Kontrak juga menawarkan beberapa semantik evaluasi, seperti mengabaikan pemeriksaan, melaporkan pelanggaran lalu melanjutkan, atau menghentikan program, alih-alih hanya dikendalikan oleh NDEBUG.

Bahasa Indonesia version →


🇯🇵 日本語

C++26 コントラクト:事前条件と事後条件の入門

標準ライブラリの強化に関する記事では、ライブラリの要件の多くが「コントラクト」として表現されていることを見ました。本稿では C++26 のコントラクトを取り上げ、それを自分のコードにどう適用できるかを探ります。

議論はシンプルな例から始まります。与えられたインデックスで std::vector から値を返す関数です。従来は、インデックスが有効であるという要件を、関数本体内の assert によって強制していました。この方法には欠点があります。要件が実装の中にあるため、宣言だけを読む人には vector とインデックスが見えても、両者の関係は見えません。また、アサーションは NDEBUG によってのみ制御され、定義されているとチェックは完全に取り除かれます。

P2900 で導入された C++26 のコントラクトは、パラメータリストの後に置かれる pre(...) 節によって、要件を関数シグネチャへ移します。この事前条件は、関数に入る時点で成り立つと想定される条件を述べます。同じ要件を宣言に記述することもでき、API を読むすべての人に見えるようになります。コントラクトはいくつかの評価セマンティクスを提供します。チェックを無視する、違反を報告して処理を続ける、プログラムを終了させる、などです。どれが利用可能で、どのように選択されるかは、コンパイラの実装によって決まります。

コントラクトはまた、呼び出し側が提供すべきものと、関数が返すと約束するものを区別します。post で導入される事後条件は、各 return 文の前に手動でチェックを書くことなく、これらの約束を表現します。そのため、実行時チェックが無効化されている場合でも、API を文書化する手段として有用です。

記事は完全な事前条件の例で締めくくられ、事後条件、宣言と定義へのコントラクトの配置、コンパイラオプション、そして開発者を驚かせるかもしれない詳細といったトピックにも触れています。

C++26 のコントラクトは assert とどう違いますか?

コントラクトは事前条件と事後条件を関数宣言に直接置くため、要件が API の中で見えるようになります。また、チェックを無視する、違反を報告して続行する、終了するといった複数の評価セマンティクスを提供し、NDEBUG だけで制御されるわけではありません。

日本語 version →


🇧🇷 Português

Contratos do C++26: introdução a pré-condições e pós-condições

No artigo sobre o endurecimento da biblioteca padrão, vimos que muitos requisitos da biblioteca são expressos como "contratos". Este post explora os contratos no C++26 e como eles podem ser aplicados ao nosso próprio código.

A discussão começa com um exemplo simples: uma função que retorna um valor de um std::vector em um determinado índice. Tradicionalmente, o requisito de que o índice seja válido é imposto com assert dentro do corpo da função. Essa abordagem tem desvantagens. O requisito fica na implementação, de modo que quem lê apenas a declaração vê um vector e um índice sem a relação entre eles. As asserções também são controladas apenas por NDEBUG, que remove a verificação por completo quando definido.

Os contratos do C++26, introduzidos pela P2900, movem o requisito para a assinatura da função com uma cláusula pre(...) posicionada após a lista de parâmetros. Essa pré-condição declara uma condição que deve valer na entrada da função. O mesmo requisito também pode aparecer na declaração, tornando-o visível para qualquer pessoa que leia a API. Os contratos oferecem várias semânticas de avaliação, incluindo ignorar uma verificação, reportar uma violação e continuar, ou encerrar o programa, sendo que a implementação do compilador determina quais estão disponíveis e como são selecionadas.

Os contratos também distinguem entre o que o chamador deve fornecer e o que a função promete retornar. As pós-condições, introduzidas com post, expressam essas promessas sem exigir verificações manuais antes de cada instrução return. Isso torna os contratos úteis para documentar APIs mesmo quando a verificação em tempo de execução está desativada.

O artigo termina com um exemplo completo de pré-condição e aborda outros tópicos, como pós-condições, a colocação de contratos em declarações e definições, opções do compilador e detalhes que podem surpreender os desenvolvedores.

Em que os contratos do C++26 diferem de assert?

Os contratos colocam pré e pós-condições diretamente na declaração da função, tornando os requisitos visíveis na API. Eles também oferecem várias semânticas de avaliação, como ignorar uma verificação, reportar uma violação e continuar, ou encerrar, em vez de serem controlados apenas por NDEBUG.

Português version →


🇷🇺 Русский

Контракты C++26: введение в предусловия и постусловия

В статье о повышении надёжности стандартной библиотеки мы видели, что многие требования библиотеки выражаются в виде «контрактов». Этот пост рассматривает контракты в C++26 и то, как их можно применять в собственном коде.

Обсуждение начинается с простого примера: функция возвращает значение из std::vector по заданному индексу. Традиционно требование корректности индекса обеспечивается с помощью assert в теле функции. У такого подхода есть недостатки. Требование находится в реализации, поэтому тот, кто читает только объявление, видит vector и индекс, но не связь между ними. Утверждения также управляются только макросом NDEBUG, который при его определении полностью удаляет проверку.

Контракты C++26, введённые через P2900, переносят требование в сигнатуру функции с помощью предложения pre(...), размещаемого после списка параметров. Это предусловие задаёт условие, которое ожидается выполненным при входе в функцию. То же требование может присутствовать и в объявлении, делая его видимым для каждого, кто читает API. Контракты предлагают несколько семантик вычисления: игнорирование проверки, сообщение о нарушении с продолжением работы или завершение программы. Какие из них доступны и как они выбираются, определяет реализация компилятора.

Контракты также различают то, что вызывающая сторона должна предоставить, и то, что функция обещает вернуть. Постусловия, вводимые с помощью post, выражают эти обещания без необходимости ручных проверок перед каждым оператором return. Поэтому контракты полезны для документирования API даже тогда, когда проверки во время выполнения отключены.

Статья завершается полным примером предусловия и рассматривает дополнительные темы: постусловия, размещение контрактов в объявлениях и определениях, опции компилятора и детали, которые могут удивить разработчиков.

Чем контракты C++26 отличаются от assert?

Контракты размещают предусловия и постусловия непосредственно в объявлении функции, делая требования видимыми в API. Они также предлагают несколько семантик вычисления, например игнорирование проверки, сообщение о нарушении с продолжением работы или завершение, а не управляются только макросом NDEBUG.

Русский version →


🇨🇳 简体中文

C++26 契约:前置条件与后置条件入门

在关于标准库加固的文章中,我们看到许多库要求都以“契约”的形式表达。本文探讨 C++26 中的契约,以及如何将其应用于我们自己的代码。

讨论从一个简单的例子开始:一个函数根据给定索引从 std::vector 中返回一个值。传统上,索引有效这一要求是通过在函数体内使用 assert 来强制执行的。这种方法存在缺点。该要求位于实现中,因此只阅读声明的人看到的是一个 vector 和一个索引,却看不到两者之间的关系。断言还仅受 NDEBUG 控制,定义该宏时会完全移除检查。

通过 P2900 引入的 C++26 契约,将该要求移入函数签名,放在参数列表之后的 pre(...) 子句中。该前置条件说明函数入口处预期成立的条件。同样的要求也可以出现在声明上,使任何阅读 API 的人都能看到。契约提供多种评估语义,包括忽略检查、报告违规后继续执行,或终止程序,具体可用的选项及其选择方式由编译器实现决定。

契约还区分调用者必须提供的内容与函数承诺返回的内容。使用 post 引入的后置条件表达这些承诺,无需在每个 return 语句之前进行手动检查。因此,即使禁用了运行时检查,契约仍有助于记录 API。

文章最后给出一个完整的前置条件示例,并涵盖后置条件、契约在声明与定义上的放置位置、编译器选项,以及可能让开发者意外的细节等更多主题。

C++26 契约与 assert 有何不同?

契约将前置和后置条件直接放在函数声明中,使要求在 API 中可见。它们还提供多种评估语义,例如忽略检查、报告违规后继续执行,或终止程序,而不是仅由 NDEBUG 控制。

简体中文 version →