#c variadic functions
Explore tagged Tumblr posts
Text
Wrote another rendition of my nicer type-safe variadic functions in C post, as a StackOverflow answer. Maybe I should roll this idea into a nicer-variadics.h and throw it up on GitHub?
2 notes
·
View notes
Text
C++ for Advanced Developers
C++ is a high-performance programming language known for its speed, flexibility, and depth. While beginners focus on syntax and basic constructs, advanced developers harness C++'s full potential by leveraging its powerful features like templates, memory management, and concurrency. In this post, we’ll explore the key areas that elevate your C++ skills to an expert level.
1. Mastering Templates and Meta-Programming
Templates are one of the most powerful features in C++. They allow you to write generic and reusable code. Advanced template usage includes:
Template Specialization
Variadic Templates (C++11 and beyond)
Template Metaprogramming using constexpr and if constexpr
template<typename T> void print(T value) { std::cout << value << std::endl; } // Variadic template example template<typename T, typename... Args> void printAll(T first, Args... args) { std::cout << first << " "; printAll(args...); }
2. Smart Pointers and RAII
Manual memory management is error-prone. Modern C++ introduces smart pointers such as:
std::unique_ptr: Exclusive ownership
std::shared_ptr: Shared ownership
std::weak_ptr: Non-owning references
RAII (Resource Acquisition Is Initialization) ensures that resources are released when objects go out of scope.#include <memory> void example() { std::unique_ptr<int> ptr = std::make_unique<int>(10); std::cout << *ptr << std::endl; }
3. Move Semantics and Rvalue References
To avoid unnecessary copying, modern C++ allows you to move resources using move semantics and rvalue references.
Use T&& to denote rvalue references
Implement move constructors and move assignment operators
class MyClass { std::vector<int> data; public: MyClass(std::vector<int>&& d) : data(std::move(d)) {} };
4. Concurrency and Multithreading
Modern C++ supports multithreading with the `<thread>` library. Key features include:
std::thread for spawning threads
std::mutex and std::lock_guard for synchronization
std::async and std::future for asynchronous tasks
#include <thread> void task() { std::cout << "Running in a thread" << std::endl; } int main() { std::thread t(task); t.join(); }
5. Lambda Expressions and Functional Programming
Lambdas make your code more concise and functional. You can capture variables by value or reference, and pass lambdas to algorithms.std::vector<int> nums = {1, 2, 3, 4}; std::for_each(nums.begin(), nums.end(), [](int x) { std::cout << x * x << " "; });
6. STL Mastery
The Standard Template Library (STL) provides containers and algorithms. Advanced usage includes:
Custom comparators with std::set or std::priority_queue
Using std::map, std::unordered_map, std::deque, etc.
Range-based algorithms (C++20: ranges::)
7. Best Practices for Large Codebases
Use header files responsibly to avoid multiple inclusions.
Follow the Rule of Five (or Zero) when implementing constructors and destructors.
Enable warnings and use static analysis tools.
Write unit tests and benchmarks to maintain code quality and performance.
Conclusion
Advanced C++ programming unlocks powerful capabilities for performance-critical applications. By mastering templates, smart pointers, multithreading, move semantics, and STL, you can write cleaner, faster, and more maintainable code. Keep experimenting with modern features from C++11 to C++20 and beyond — and never stop exploring!
0 notes
Text
When you're making a game engine, there's a tradeoff when it comes to working on dev quality-of-life features vs game-facing features.
A factor I don't usually see discussed is the project's PITA Budget. It may take more swe-hours to implement a shortcut that saves 5 seconds at a time than it will ever pay back, but the qualitative difference in working without that 5s annoyance reduces the mental-strain cost of continuing to work on the project at all. As a motivation-bottlenecked solo dev, having good tools not only makes asset creation more efficient, but effectively gives you more hours in the month to work with.
today's small thing is interpreting a UI Label of just "\n" to be a shortcut for a linefeed, which lets us change this from
to
cutting lines-of-code in half
It's the sort of thing that makes actually* zero difference in the finished product, but it makes the daily life of being a game developer fractionally less frustrating, so that's satisfying.
*: If compilers can optimize across strcmp, which I strongly suspect they can, then they would literally compile into the same code
For funsies (because I'm stoned) let's pretend we're compiler engineers again. Why should this be optimizable? ui.labels() is a variadic template function that emits one call to ui.label() per argument, which has overloads for each type. the const char* overload has a clause at the top of it:
With inlining, we would get if (strcmp("\n", "\n") == 0), which a human programmer can clearly see is always true. Can compilers? Well, given that strcmp is a C Standard Library function, compilers are free to make special assumptions about how they work that may not be obvious from the type signature. We also would not be able to inline strcmp, because it's compiled separately (unless you're building your own libc from source, or if your libc ships bitcode which would be weird)
Anyway! So it stands to reason that some enterprising young lad may have realized that they can save 0.2ms on some benchmark by constant-folding strcmps, or by precomputing string manipulations, or whatever. How can we check? Godbolt.
Sure enough, even at -O1 clang is able to constant-fold the strcmps and turn test("foo") into just doSomethingElse()
This ramble didn't really have much of a point. C++ is a language built around zero-cost abstractions. There's something really satisfying about knowing enough about how the optimizer works, and what the language's semantics are, including its cost model, and thus being able to reason about what will actually get optimized away in practice.
0 notes
Text
Godot 4.0 hack for easy vaargs/variadic functions
(had to make a correction, original code was broken) I wanted to make a script to print out all my nonsense signals. I couldn't figure out a way to do that sensibly, so here's a kind of Faustian hack. I couldn't get the code in here formatted nicely, so here it is in a big heap: func _ready(): connect_signals()
#this is of course an extremely silly way to do this
func print_signal(a='~',b='~',c='~',d='~',e='~',f='~',g='~',h='~',i='~',j='~'): var output = '' var last = '' for x in [a,b,c,d,e,f,g,h,i,j]: if not x is String or x != '~': # hopefully we're not using '~' much output += last last = str(x) set_text('%s : %s\n%s' % [last, output, text])
func connect_signals(): # we could use unbind if print_signal had less args, but that would lose information #if make_storage_connection: Events.make_storage_connection.connect(print_signal.unbind(3)) if make_storage_connection: Events.make_storage_connection.connect(print_signal.bind('mk_strg_con'))
#godot#godot engine#godot 4.0#variadic FUNctions#vaargs#gdscript#future_debugging_missadventure#getting emails from OHSA about type safety
0 notes
Text
C Functions
When it comes to programming in C, functions are an essential building block. They allow you to break down your code into manageable pieces, promote code reusability, and make your programs more organized. In this article, we will delve into the world of C functions, covering topics like return types, parameters, passing arguments by value and by reference, variadic functions, and function prototypes.
0 notes
Link
Programming, Problem Solving, Project Building, and Design Skills. 7X Quizzes, Practice, Hmwk & REAL Projects than others
What you’ll learn
Mastering 4 critical SKILLS using C++ 17
Deep Dive with C++ 11/14/17 Modern Syntax from basic to advanced
EXTENSIVE practice and homework sets to master the key concepts
MANY Projects from easy to hard with their solutions for projects-building skills
MANY Quizzes to master the concepts
FOUR critical skills to master not just one
A proven curriculum: Many of my thousands of students highly recommend it
Short lectures, to the point, comprehensive and easy to get in an iterative style
Learn from Ph.D. holder in AI: Teaching, Training & Coaching for many years
Requirements
Passion for building things!
Passion with problem-solving!
Access to a computer.
Description
Almost all other courses focus on knowledge. In this course, we focus on 4 critical skills.
Overall:
The course covers basic to advanced modern C++ syntax. Beginners in C++ will learn a lot!
The course helps you master the 4 most important skills for a programmer
7+ times practice & homework compare to other courses + 6 projects
Special Teaching style: iterative, easy, and short
This is an English Course only. 1/3 Course now has Manual English subtitles. Remaining under-progress.
Programming skills
Problem-solving skills: rarely covered by other courses
Project building skills: partially covered by other courses
Design skills: rarely covered by other courses
Content
Basic to advanced modern C++.
A huge set of Quizzes, Practice, Homework, and Projects
Fundamentals: Variables, Loops, Control Flow, Functions, Recursive Functions, Arrays
Advanced Topics: Pointers, STL, Templates, Headers, and Includes, Exception Handling, Compilation Process, Debugging
Object-Oriented Programming (OOP): Classes, Objects, Inheritance, Polymorphism, Operator Overloading
Modern Topics in C++11/C++14/C++17:
Design: Several principles and patterns are embedded in the homework & projects
Move Semantics, Perfect Forwarding, Variadic Template, Folding expressions, Smart Pointers, Lambda Expressions, Wrappers (Optional, Variant, Any), Uniform initialization, except, Structured Binding, Nested namespaces, misc.
OOP: Member initializer, Defaulted and Deleted Functions, Delegating constructors, Inheriting Constructors
STL: Forward list, Initializer list, Array, Unordered containers
2 styles of homework: Algorithmic (problem-solving) and applications
Several software design concerns are embedded in the homework.
So you are getting introduced to Software Engineering & Design Patterns
Several quizzes to master the concepts
Building Skills: Practice, Homework, and Projects
One unique feature in this course is my education strategy:
Each video smoothly explains a simple concept(s)
Typically followed by easy to medium practice to administrate the concept
Then typically followed by an easy-medium-hard set of homework questions to challenge you
Extensive homework from easy to medium to hard to help to build the skills.
Most of the practice/homework questions are unique in this course
Small-to-large set of projects to build up project building and design skills
Solutions to all of them.
Explain, Administrate & Challenge
Programming questions are mainly from my competitive programming experience
OOP questions are mostly invented to achieve several goals:
Mastering the OOP concepts
Enforcing a lot of design heuristics & OOD
Preparing you for design principles and patterns
By the end of the journey
Solid understanding of programming concepts using C++
Mastering the target 4 skills
With the administered problem-solving skills
With the administered project-building and design skills
More career options such as games or embedded development.
You can start competitive programming smoothly in Div2-A/B Code forces
Smooth start in Data Structure course
Smooth start in Algorithms course
Smooth start in Software Engineering course
Later, smooth start in one of the technology tracks in frontend or backend
Don’t miss such a unique learning experience!
Download
To download more paid course for free visit the course catalog where you will 1000+ paid courses available for free. You can get full course into your device with just a single click. Follow the above link to download above course.
2 notes
·
View notes
Text
Noteworthy Programming languages to Consider for Blockchain App Development!
Blockchain app development is gaining momentum at a fast pace and this trend is here to stay. Blockchain solutions have proven their worth as game-changers in almost every industry vertical. Here are some interesting stats on Blockchain adoption as researched by the online portal DEMANDSAGE:
As of January 2023, more than 85 million global users had Bitcoin block explorer Blockchain wallets.
As recorded in January 2023, the average Bitcoin transactions executed in one single day were between 291015 and 205314.
By the year 2024, the global expenditure on Blockchain apps and solutions will reach $19 billion
Developing a disruptive Blockchain application or solution is a lucrative option for entrepreneurs and investors. However, businesses planning to build a Blockchain solution should understand the basics of Blockchain programming before jump-starting their project or proceeding to hire Blockchain app development services. This post discusses the offerings of the top Blockchain programming languages. After reading this post you will be able to figure out which language would be the best fit for your Blockchain use case.
Top Programming Languages For Blockchain Development
Solidity
Solidity is an object-oriented Blockchain programming language specifically designed to create smart contracts and decentralized applications that run on the EVM (Ethereum Virtual Machine). Ethereum is a massive computing platform based on Blockchain; its ecosystem is one of the most crucial components of Blockchain app development. The creators of Ethereum have developed Solidity and provide active support to this high-level programming language for fulfilling their in-platform requirements. Influenced by other programming languages like Java, JavaScript, Python, and C++; Solidity has proved its worth as one of the best languages for writing smart contracts.
Features
Solidity is flexible, stable, and promises a good accuracy rate. It comes with numerous disruptive features like variadic return and static typing. It supports concepts such as user-defined functions, inheritance properties, and libraries. Solidity comes with an easy learning curve and enables access to tools like debuggers, JS infrastructures, etc. Solidity has several type-safe functions due to the presence of ABI (Application Binary Interface).
Use Cases
Solidity is used for developing Ethereum smart contracts and Chainlink smart contracts. Chainlink is a decentralized Oracle network used for on-chain as well as off-chain Blockchain computations. Another use case of Solidity is the compound protocol on Ethereum Blockchain. This is an autonomous interest rate protocol involving algorithms. Solidity is also used for developing Uniswap. Uniswap is a decentralized crypto trading platform involving a network of decentralized finance apps governed by a community.
Python
Python is one of the most popular Blockchain programming languages. Its robust nature and versatility speed up the development time. Python has a simple English-like syntax that reduces the lines of coding and so, is a perfect pick for newbie coders. Python programming suits both approaches – scripting, and base. It is a high-level language that can be effortlessly integrated with other programming languages like Java, C++, etc. It functions on various platforms including Mac, Linux, Windows, and Raspberry.
Features
Python is object-oriented, easy to code, and extensively portable. It offers strong open-source language support, OOP support, rapid prototyping, access to a dynamic architecture, and dynamic memory allocation. The availability of multiple online resources like libraries, plugins, and development manuals facilitates Blockchain app development; developers get the solution to almost every issue faced during Blockchain projects. Libraries like Numba speeds up coding without compromising on crucial factors like security and performance. Python fares better in performing complicated mathematical operations and handling Big data as compared to most other programming languages.
Use Cases
It is used to write smart context for Hyperledger Fabric, NEO contracts, Steemit, and develop cryptocurrencies like Ethereum and Bitcoin.
Java
This is a popular platform-independent Blockchain programming language that is widely used for developing decentralized applications and smart contracts. The language is derived from C-Syntax and functions on the WORA (Write Once Run Anywhere) concept. Its ubiquitous nature allows one to use Java for almost every web system. As such, the code written by programmers is highly portable and can be run on every device that has JVM (Java Virtual Machine).
Features
Java’s offerings are manifold. Its Portability makes it an apt choice for Blockchain development projects. Java comes with an extensive API (Application Programming Interface), that includes multiple Java classes, packages, and interfaces. Owing to its multi-threaded nature, you utilize the CPU to the fullest. It’s a developer-friendly language and can support heavy APIs like object-oriented programming based on its class. Java offers adequate libraries and simplifies the process of memory cleaning. Using Java’s security manager, you can define access rules for a specific class; this minimizes the chances of security vulnerabilities. Java’s programming is based on Java Virtual Machine and is not dependent on any specific system-based infrastructure. Hence, its capabilities are not limited by a device’s architecture and it can handle a huge number of users on a Blockchain network simultaneously.
Use Cases
The use case examples include creating Blockchains on platforms like Hyperledger Fabric, Ethereum, NEO, IOTA, etc.
JavaScript
JavaScript is a popular web language and is pre-installed in most PCs and so, it becomes easy to build Blockchain solutions with JS.
Features
JavaScript is a lightweight, object-oriented, and prototype-based scripting language that provides support for functional programming. JS can easily handle asynchronous actions and the communications taking place between nodes. It comes with a wide range of tools and libraries that facilitate Blockchain app development.
Use Cases
Using JavaScript, Blockchain app developers can connect an app’s front end to Ethereum’s network and smart contracts. JS is has also been used in Hyperledger Fabric.
PHP
PHP (Hypertext Preprocessor) is an open-source and object-oriented programming language that can be used to develop Blockchain solutions of various complexity levels. The language is straightforward and simple and offers an easy learning curve.
Features
PHP is platform-independent and powered by the Zend Engine; so, it can be written on a wide variety of OSs. It offers a highly configurable library that comes in handy for developers. Its interactive pages enable one to sail through complex requirements. PHP has a built-in database connection module; this reduces the hassles and speeds up the development time during web development projects.
Use Cases
PHP is used for smart contract development.
Go
This Google-developed language has gained traction as one of the top Blockchain programming languages. Go is an open-source and statically typed language. It offers benefits like speed, user-friendliness, flexibility, and scalability that make it suitable for Blockchain development.
Features
Go comes with a powerful library containing functions & packages. It provides organized syntaxes. It enables you to run multiple processes simultaneously without compromising on memory resources. Despite being a static language, Go gives developers a feel of being dynamic.
Use Cases
Examples of its use cases are Go-Ethereum (Ethereum-based project written in Go) and GO-Hyperledger Fabric.
Ruby
Ruby is a high-level and general-purpose programming language that comes with cross-platform compatibility. This open-source language is developer-friendly and focuses on simplicity and high productivity. It can be installed in Windows & POSIX and can be connected to Oracle, MySQL, Sybase, and DB2.
Features
Ruby is a multi-paradigm language that has exceptional memory allocation abilities. It is an interpreted and scripting language. The feature of multiple-language adaptability makes Ruby a good choice for Blockchain app development.
Use Cases
Ruby allows developers to program Blockchain solutions using third-party plugins and APIs.
Rholang
Rholang is newer as compared to other Blockchain programming languages. It comes with an easy-to-understand syntax. It is reliable, speedy, and user-friendly and provides high accuracy levels. Rholang employs a functional programming approach instead of an object-oriented programming approach.
Use Cases
Rholang is used for developing smart contracts and other high-end Blockchain-based projects.
Simplicity
This language was designed to minimize the low-level understanding of cryptocurrencies. Simplicity is reliable and offers the security of funds, an offering that provides it an edge over many other Blockchain programming languages. Simplicity is in harmony with the “Elements platform” of Blockstream. Simplicity is a viable option for creating sophisticated and secured smart contracts in Blockchain environments.
Use Cases
Simplicity is compatible with the Blockchain-based platform Ethereum. It reduces the complex functionality of the Bitcoin Script by enabling a low-level understanding of the Bitcoin Script. It’s a good option for coding smart contracts.
SQL
SQL (Structured Query Language) is one of the most recent Blockchain programming languages that can be used for creating secure and effective solutions. This is an IBM-created language meant for facilitating communication with databases like SQL Server, MySQL, Oracle, and PostgreSQL. With SQL, users can store data queries and also manipulate and raise those queries.
Use Cases
Aergo is an important use case of Blockchain development in SQL. It is a Blockchain project that offers ready-to-use solutions to companies that work with technologies like Coinstack or Blocko. SQL can also be used for developing robust business-centric smart contracts.
CX
CX is one of the most sought-after Blockchain programming languages that can function as a contractual digital intermediary.
Features
Its features include a simplified error control process and access to pointers, arrays, and propelled cuts. CX enables developers to effortlessly manipulate programs and apply vectors, pointers, forced reductions, etc.
Use Cases
CX when integrated with the programming language Go, gives businesses an escape from critical issues like discretionary code execution steps. CX integrates well with Open Graphics Library (OpenGL). This integration is leveraged by Blockchain developers to gain advantages regarding GPU capacity.
C++
C++ is a general-purpose programming language that can be used for creating a wide variety of applications like finance solutions, AR/VR apps, 3D gaming apps, etc. It is a robust, flexible, & object-oriented programming language that is capable of managing resource-intensive apps smoothly. It’s a multi-paradigm language and follows the OOPs technique. This language is developer-friendly and offers ease of usage. C++ is one of those Blockchain programming languages that promises a faster execution time.
Features
Its offerings include efficient memory control, function overloading, and effective CPU management. C++ can effortlessly run parallel and non-parallel threads. It can isolate the code for different data structures as well. The capability of run-time polymorphism results in improved app performance. Its data-hiding capability strengthens the security quotient. There’s also the option for moving semantics to copy data productively.
Use Cases
C++ is used for developing smart contracts on the EOS Blockchain and developing cryptocurrencies such as Stellar, Litecoin, Bitcoin, EOS, and Ripple.
C#
C# is an open-source and object-oriented programming language created by Microsoft. It happens to be one of the most popular Blockchain programming languages. It can be used to build scalable applications with .NET compatibility. C# is a great pick for crafting powerful codes with cross-platform compatibility.
Features
C# is an Extensible Markup language and can function as a support for distributed systems. With this language, programmers can create highly portable codes that run on a wide variety of hardware and OSs including Windows, Mac, Android, Linux, etc. The assembly control feature makes it easier for developers to handle issues like version control. The OOPs feature in C# helps in optimizing the performance of Blockchain solutions and apps.
Use Cases
C# has been used in NEO in combination with other programming languages such as Python, JavaScript, Java, & Go. C# has been used Stratis. This is a Blockchain-as-a-service providing platform powered by Microsoft. IOTA, an open-source distributed ledger and cryptocurrency, is another use case example.
Vyper
Vyper is one of the newest Blockchain programming languages. It is compatible with EVM and its syntax is similar to that of Python 3’s. Vyper can be used as an alternative to the popular Blockchain programming language Solidity.
Features
Vyper comes with an exceptional control structure that enables handling security challenges more effectively. Its other offerings include modifiers, recursive calling, etc.
Use Cases
Vyper is used for the Ethereum Virtual Machine (EVM) and for developing smart contracts.
Concluding Views:
All the aforementioned Blockchain programming languages come with distinct offerings and are suitable for specific use cases. You need to pick the language based on your use case requirements. A thorough knowledge of the offerings of these languages will help you to make the right decision while choosing the tech stacks for your Blockchain project. A good understanding of these programming languages will also prove beneficial when you’re discussing tech stack selection, with the Blockchain App Development Company to whom you’ve outsourced your project.
0 notes
Text
VARIADIC FUNCTIONS IN C – HACKER RANK SOLUTION
VARIADIC FUNCTIONS IN C – HACKER RANK SOLUTION
Click here to Read.
View On WordPress
0 notes
Text
[Solved][C++] cannot pass non-trivial object of type 'std::__1::string' (aka 'basic_string') to variadic function; expected type from format string was 'char *'
[Solved][C++] cannot pass non-trivial object of type ‘std::__1::string’ (aka ‘basic_string’) to variadic function; expected type from format string was ‘char *’
Problem If you want to print a string data type variable in C programming language, you can use the following code: (more…)
View On WordPress
0 notes
Text
C had printf() before it had variadic functions (mentioned here). You apparently couldn't write your own function that took a variable number of arguments.
Not sure if these count:
Rust's Box type is special in a way that affects the type system, though you only notice if you pay very close attention.
PHP has builtin syntax that masquerades as functions. Like empty(), which doesn't require its argument to be defined: empty($x) is ok even if $x doesn't exist, and empty($x[1]) is ok even if $x doesn't have 1 as a key.
Various Lisps have "special forms", which look like functions and macros but aren't. "if" (and/or "cond") is a special form because it needs lazy evaluation and you can't do that as a macro.
Python's static typecheckers have special knowledge about many builtin functions. (This has zero relevance to what happens at runtime.)
Python's super() steals arguments from the environment in a way you can't really replicate.
A question for the programming side of Tumblr
In the Go programming language, the type system doesn't allow generics, but in order to be at all a usable language they had to at least have arrays and hashmaps that weren't type-specific, so there are a number of built-in functions like copy(l1, l2) which ARE generic - the type signature of copy in a different type system might be written as `(T[], T[])->int`; but this type is not expressible in Go.
My question is, are there languages besides Go that have built-in functions whose types cannot be expressed in the language's own type system? It seems like a weird thing to do, and I can't think of any other examples of this off the top of my head, but maybe there are obvious ones that I'm missing.
#I started learning Go very recently#I may come to hate it in the future#but right now I appreciate it as a sort of anti-Rust#it's good to know what you can get away with half-assing
114 notes
·
View notes
Text
Variadic Functions in C
A Nicer Approach
So I've described the problem, and even why it maybe makes sense for that problem to exist at the low level of the language definition, but we can do better for actual humans writing C.
As of C99, we have variadic macros, and we have compound literals. This means that we can wrap variadic functions in macros that automate two common conventions for variadic functions:
pass a magic end-of-arguments value, or
pass the number of variadic parameters.
Let's take a function like `execl` for example: it takes some number of `char *`, and it expects the last one to be a null pointer. Behold:
#define EXECL(...) execl(__VA_ARGS__, (char * )0)
Boom. Problem solved. No more segfaults or stack corruptions or exploitable code execution vulnerabilities in your code just because you forgot to put a null pointer at the end, or forgot to cast it to the a pointer type with a compatible representation.
Now how do you count arguments? Well, if your arguments are all of the same type, or implicitly convertible to the same type, you can throw them into a compound literal for an array of that type and take the size of that array:
#define ARGUMENT_COUNT(type, ...) (sizeof((type[]){__VA_ARGS__}) / sizeof(type))
So then if you have a function like this:
int sum(size_t argument_count, ...)
You can wrap it like this:
#define SUM(...) sum(ARGUMENT_COUNT(int, __VA_ARGS__), __VA_ARGS__)
Same benefit: the function receives an automatically computed-at-compile-time first argument of how many parameters the wrapper macro call received. And since the stuff inside a `sizeof` operator is not evaluated - only the type of the expression is statically figured out per compile-time C rules - you don't get any of the problems with macros evaluating their arguments multiple times.
7 notes
·
View notes
Text
C++: generating a native interface automatically
C++: generating a native interface automatically
When you write a programming language translator, it is useful to be able to connect to the underlying system easily. In this post, I will show how modern C++ makes it possible to entirely automate this process. Using variadic templates, it is possible – and relatively easy – to let the compiler generate all the boilerplate code connecting your translator to any native C function. Adding a C…
View On WordPress
0 notes
Link

Key Takeaways
PHP 7.0 added scalar type declarations for strings, integers, floating-point numbers, and booleans
PHP 7.0 added support for return type declarations
PHP 7.1 added support for nullable parameter types and return types
void is a valid return type as of PHP 7.1
PHP 7.1 added a new compound type called iterable
PHP 7.4 adds support for typed properties, which is types for class properties
We have already explored some of the improvements introduced in PHP 7.x in two articles: PHP 7 — Getting Started and OOP Improvements and PHP 7 — Classes and Interfaces Improvements. To set the background for this article on PHP’s type system, PHP is a weakly typed language, which implies the data type of variables does not need to be declared.
In this article we explore new type-related features available in PHP 7.x.
Scalar Type Declarations
Type declarations are nothing new to PHP. Type declarations are used to annotate function parameters and annotated parameters require an argument to be of the specified type. Support for type declarations for class, interface, and self was added in PHP 5.0.0, while support for type declarations for array was added in PHP 5.1.0, and upport for type declarations for callable was added in 5.4.0.
PHP 7.0 added support for scalar type declarations for types string (strings), int (integers), float (floating-point numbers), and bool (booleans).
To demonstrate type declarations with an example, create a script (typedeclr.php) in the document root directory and copy the following listing to the script:
<?php class A {} class B extends A {} class C {} function f(A $a) { echo get_class($a)."\n"; } f(new A); f(new B); f(new C); ?>
Class B extends class A. Class C does not extend any class and defines a function f() with a parameter of type A. Then, the script invokes function passing instances of class A, B and C successively as arguments. Assuming the same setup as in the first article PHP 7 — Getting Started and OOP Improvements, run the script with url http://localhost:8000/typedeclr.php. While calling f() passing instances of classes A and B does not generate an error and outputs the value defined in function, calling f() with an argument of type C generates a TypeError:
AB
Uncaught TypeError. Argument 1 passed to f() must be an instance of A, instance of C given
Now, let’s discuss scalar types. Scalar types come in two kinds,��coercive (default) and strict. Create a script sumints.php and define a vararg function taking parameters of type int. Invoke the function with some of the arguments supplied as floating-point numbers and others as string, for example:
echo SumInts(1,'3',0,3.6);
The sumints.php script is listed below, including a commented-out declare directive that we will discuss later when we cover strict scalar types
<?php //declare(strict_types=1); function SumInts(int ...$ints) { return array_sum($ints); } echo SumInts(1,'3',0,3.6); ?>
If you run the script, it will output the sum of the args converted to integer values. In other words, wrong type arguments get converted (coerced) to the expected type. A value of 9 is output for the sumints.php as shown in Figure 1.

Figure 1. Output from sumints.php
Floating-point numbers are converted to an integer by removing the fractional value. As an example 3.6 becomes 3 and does not get rounded off to 4. String value ‘3’ gets converted to 3.
Strict scalar type declarations work in a completely different way. First off, strict mode is available only for scalar type declarations and not for class, interface, callable, or array type declarations. Go back to the previous script and comment in the declare() directive to use strict scalar type declarations. Notice that the declare() directive must appear at the top of the file in which strict mode for scalar type declarations is to be used.
declare(strict_types=1);
Run the script again and you will see a TypeError is raised. The TypeError indicates that the arguments must be of type int.
Uncaught TypeError: Argument 2 passed to SumInts() must be of the type int, string given
Strict mode does not apply to function calls from internal (built-in) functions.
When using coercive mode (the default mode) for scalar type declarations, a null value argument does not get coerced or converted to the expected type and a TypeError is thrown instead. To demonstrate this, create a script sumints_null.php in which a function expecting an integer value is supplied a null arg:
<?php function SumInts(int ...$ints) { return array_sum($ints); } echo SumInts(1,'3',0,null); ?>
If you run the script, you will get a TypeError.
Uncaught TypeError: Argument 4 passed to SumInts() must be of the type int, null given
If you want to allow for a null argument, you must specify a null default value for the corresponding parameter as in the script listed below:
<?php function SumInts(int $a=null) { return array_sum($a); } echo SumInts(null); ?>
With strict mode, argument values must be of the type defined in the function with one exception: integer values may be supplied to a function expecting a float.
To demonstrate this, create a script sum_floats.php in which a variadic function with float type parameters is defined. Invoke the function passing integers for some of its arguments:
<?php declare(strict_types=1); function SumFloats(float ...$floats) : float { return array_sum($floats); } echo SumFloats(1.1,2.5,3); ?>
Run the script to have the result, the float number 6.6, printed out. In this case, the int values get converted to float.
Our next example will show how to use strict scalar type declarations with float type. Create a script sumfloats.php and define a function with two parameters of type float and return type int. Return type declaration is another new feature and is discussed in more detail later on, we will just assume they are ok for this example. The function returns a value by adding its two arguments. Invoke then the function with one argument of type int and the other of type string:
<?php declare(strict_types=1); function SumFloats(float $a, float $b) : int { return $a + $b; } echo SumFloats(1,'3'); ?>
If you run the script, a TypeError is generated indicating that an argument passed to a function must be of type float while a string was given.
Uncaught TypeError: Argument 2 passed to SumFloats() must be of the type float, string given
If you remove the declare directive for strict mode and run the script again, coercive mode will give you an output value of 4.
Scalar type declarations may be used with strings. Create a script reverse.php and add a function to it that takes a string parameter, reverses it, and returns the resulting string. Using a try/catch block, invoke the function with a floating-point value 3.5:
<?php function Reverse(string $a) { return strrev($a); } try{ echo Reverse(3.5); }catch (TypeError $e) { echo 'Error: '.$e->getMessage(); } ?>
If you run the script, you will get a value of 5.3 in coercive mode. If you add the directive declare(strict_types=1); for strict mode and run the script again, an Error is raised:
Error: Argument 1 passed to Reverse() must be of the type string, float given
Strict typing for scalar type declarations only applies to function calls from within the file in which strict typing is enabled and not to function calls from another file that does not declare strict typing. Similarly, if the file that makes the function call also has strict typing enabled, strict mode is used.
To demonstrate, create a PHP script reverse_2.php with strict mode enabled. Add a function (called Reverse) that reverses and returns a string parameter value:
<?php declare(strict_types=1); function Reverse(string $a) { return strrev($a); }?>
Create now another script reverse_1.php that requires the reverse_2.php script and invokes its Reverse function with a floating point value:
<?php require_once('reverse_2.php'); echo Reverse(3.5); ?>
Run the reverse_1.php script. As strict mode is enabled in reverse_2.php, one might expect that a TypeError would be generated as the function that expects a string value is invoked with a floating point value. But reverse_1.php uses weak typing and a floating point value is returned with an output of 5.3. On the contrary, if strict mode is enabled in reverse_1.php, strict typing is applied and a TypeError generated:
Uncaught TypeError: Argument 1 passed to Reverse() must be of the type string, float given
Our next example deals with scalar type declarations for the boolean type. Create a script test.php with strict mode enabled and add a function that accepts a parameter of type bool and simply returns the unaltered parameter value. Invoke the function with a string value ‘true’:
<?php declare(strict_types=1); function test(bool $param) {return $param;} echo test('true') ?>
Running the script in a browser will give you a TypeError.
Uncaught TypeError: Argument 1 passed to test() must be of the type bool, string given
If the declare directive for strict mode is commented out or removed and the script is run again, coercive mode is applied. In this case, the string ‘true’ gets converted to the bool value true and the output will be 1.
Now, we will go deeper about the use of NULL values with scalar type strings.
Create a script string_null.php containing two functions, each of which takes a string argument. One of the functions has the default argument value set to NULL and the other function has no default value set. Invoke each of the functions with a string value, no value, and null value:
<?php function string_null_1(string $str) { var_dump($str); } function string_null_2(string $str = NULL) { var_dump($str); } string_null_1('a'); string_null_2('b'); string_null_1(); string_null_2(); string_null_2(null); string_null_1(null); ?>
If you run the script, string_null_1 will generate an error when invoked with no argument.
Uncaught ArgumentCountError: Too few arguments to function string_null_1(), 0 passed in
Comment out the function call that generates the preceding message and run the script again. You will see that the function calls providing string type arguments output a string, as expected. Calling string_null_2, which has a default value set to NULL, with no arguments outputs NULL. Calling string_null_2 with a NULL value as argument also outputs NULL, as expected. Calling string_null_1() passing NULL generates a TypeError, instead, since the NULL argument does not get converted to a string in coercive mode.
Return Type Declarations
As we briefly mentioned above, PHP 7.0 added support for return type declarations, which are similar to parameter type declarations. The same PHP types may be used with return type declarations as with parameter type declarations. To demonstrate the use of return type declarations, create a script reverse_return.php that declares a function with a parameter of type string and string return type.
<?php function Reverse(string $a) : string { return strrev($a); } try{ echo Reverse('hello'); }catch (TypeError $e) { echo 'Error: '.$e->getMessage(); }?>
Invoke the function with input value “hello” and the reversed string olleh gets output. The strict mode directive that is used for scalar type declarations is also applied to return type declarations. To demonstrate this, create a script reverse_return_strict.php and add the strict mode directive at the beginning. Add then a function that takes a string parameter and returns a string value. Instead of returning a string value, make the actual value returned be an integer:
<?php declare(strict_types=1); function Reverse(string $a) : string { return 5; } try{ echo Reverse("hello"); }catch (TypeError $e) { echo 'Error: '.$e->getMessage(); } ?>
Invoke the function with a string value. Running the script will generate an error:
Error: Return value of Reverse() must be of the type string, int returned
If you remove the strict mode declaration, thus switching to coercive mode, and run the script again, you will see the value ‘5’ is printed out. In this case, the int value returned is cast to a string due to weak typing.
In coercive mode, the return value gets converted to the expected return type if needed. Modify the script and declare the function return type to be an int, but actually return a string ‘5’, instead.
<?php function Reverse(string $a) : int { return '5'; } try{ echo Reverse("hello"); }catch (TypeError $e) { echo 'Error: '.$e->getMessage(); } ?>
Invoke the function passing a string value. In this case, the int type value 5 is returned after being converted from the string value ‘5’. For the conversion to be made in coercive mode, the returned value has to be convertible to the declared return type. As an example of that, if you declare an int return type and return the string ‘five’, an error is generated.
Return value of Reverse() must be of the type int, string returned
While scalar type declarations are new in PHP 7, class type declarations are not supported yet. Class types may be used in return type declarations, though, as we shall demonstrate next.
Create a script return_obj.php and declare a class Catalog including some variables typical of a magazine catalog. Instantiate the class and set values for its variables. Declare then a function with return type Catalog taking a single parameter of type Catalog. In the body of this function, just return the input argument itself:
function getCatalog(Catalog $catalog): Catalog { return $catalog; }
Invoke the function with a Catalog class object and then output the returned value.
var_dump(getCatalog($Catalog1));
The return_obj.php script is listed:
<?php class Catalog { public $title; public $edition; } $Catalog1 = new Catalog(); $Catalog1->title = 'Oracle Magazine'; $Catalog1->edition = 'January-February2018'; function getCatalog(Catalog $catalog): Catalog { return $catalog; } var_dump(getCatalog($Catalog1)); ?>
Running the script will output the Catalog class object field values, as shown in Figure 18.
object(Catalog)#1 (2) { ["title"]=> string(15) "Oracle Magazine" ["edition"]=> string(20) "January-February2018" }
As we discussed in the first article in this series, Getting started and OOP improvements, class inheritance in PHP 7.2 supports one-level return type covariance and contravariance to no type. As you remember, covariance for return type makes it possible to provide a narrower return type, while contravariance for parameter types makes it possible to provide a more generic parameter type. PHP 7.4 added full support for covariance and contravariance.
To demonstrate this, create a script return_type_inheritance.php. Add a class Catalog with a function declaring a parameter of type string and no return type. Create another class CatalogMagazine that extends the Catalog class. The return type of the function is string and the parameter type is omitted, relying on PHP 7 parameter type widening support. Instantiate each class and invoke the function to output the value returned:
<?php class Catalog { public function printItem(string $string) { return 'Catalog: ' . $string . PHP_EOL; } } class CatalogMagazine extends Catalog { public function printItem($string) : string { return 'CatalogMagazine: ' . $string . PHP_EOL; } } $catalog = new Catalog(); $catalogMagazine = new CatalogMagazine(); echo $catalog->printItem('Catalog'); echo $catalogMagazine->printItem('CatalogMagazine'); ?>
Running the script will output the return value of the functions defined in each class object:
Catalog: Catalog CatalogMagazine: CatalogMagazine
Nullable Types
It is not uncommon for null values to be passed as function parameters or returned from a function. The null type in PHP has only one value and it is case-insensitive NULL.
PHP 7.1 has added support for nullable parameter types and nullable return types. Prefix a parameter or return type with a question mark ? to make it nullable. To demonstrate the use of the nullable type create a script hello-nullable.php. Define a function hello() specifying a nullable return type. Nullable does not imply the function has to return null, though, so let’s return an actual value:
function hello(): ?string { return 'Hello'; }
Define now another function with nullable return type that actually returns NULL:
function hello_return_null(): ?string { return null; }
Finally, define a function with a nullable parameter type:
<?php function hello(): ?string { return 'Hello'; } echo hello(); echo "<br/>"; function hello_return_null(): ?string { return null; } echo hello_return_null(); echo "<br/>"; function hello_null_arg(?string $name) { return 'Hello'; } echo hello_null_arg(null); echo "<br/>"; ?>
Running the script will produce the following output:
Hello
Hello
The second function call produces no output because echo converts its argument to a to string and null does not have any corresponding string value. If var_dump() is used instead of echo a NULL value should get the following output:.
Hello
NULL
Hello
Next, we shall demonstrate with an example that if the return type of a function is a class type, null cannot be returned. Create a script return_null.php and copy the following listing:
<?php class Catalog { public $title; public $edition; } $Catalog1 = new Catalog(); $Catalog1->title = 'Oracle Magazine'; $Catalog1->edition = 'January-February2018'; function getCatalog(?Catalog $catalog): ?Catalog { return $catalog; } function getCatalog_2(?Catalog $catalog): ?Catalog { return null; } function getCatalog_3(?Catalog $catalog): Catalog { return $catalog; } var_dump(getCatalog(null)); var_dump(getCatalog_2(null)); var_dump(getCatalog_3(null)); ?>
The script declares a class Catalog with two fields. The script creates an instance of the class and sets its field values to initialize it. All three functions in the script declare a nullable parameter of type Catalog. Two of the functions have nullable return type Catalog and one function has non-nullable return type Catalog. Each of the functions is invoked with a null argument and the call is enclosed in var_dump().
As the output indicates, if the return type is nullable and a null argument is passed, the return value is null whether the actual argument or null is returned. But if the return type is a class type such as Catalog and null is returned, an error is generated indicating that return value must be an instance of the class type, in the example Catalog:
NULL NULL
Uncaught TypeError: Return value of getCatalog_3() must be an instance of Catalog, null returned
Using void as Return Type for Functions
As mentioned, support for return type declarations was added in PHP 7.0, while PHP 7.1 introduced the void return type. In a function returning void, the return statement should either be empty or omitted altogether. NULL is not to be confused with void type. NULL is a value for the null type, while void implies the absence of a value.
To demonstrate the use of a void return type, create a script hello-void.php and copy the following listing into that file:
<?php function hello(): void { echo 'Hello'; return; } echo hello(); echo "<br/>"; ?>
The script declares a function called hello() with return type void. The function outputs a ‘Hello’ string and has an empty return statement. If the return type is void the function must not return a value. Run the script, “Hello” is output.
Next, we demonstrate that a function with return type void is not allowed to return a value, not even NULL. Create a script return_void.php and declare a class Catalog containing a function with return type void that returns NULL. Invoke the function passing an instance of Catalog as an argument. The return_void.php script is listed here:
<?php class Catalog { public $title; public $edition; } $Catalog1 = new Catalog(); $Catalog1->title = 'Oracle Magazine'; $Catalog1->edition = 'January-February2018'; function getCatalog(Catalog $catalog): void { return NULL; } var_dump(getCatalog($Catalog1)); ?>
Running the script will output an error message.
A void function must not return a value (did you mean "return;" instead of "return null;"?)
Modify the script slightly so that the function has an empty return statement, which is valid for the void return type. Invoke the function with an instance of Catalog as an arg.
function getCatalog(Catalog $catalog): void { return; } var_dump(getCatalog($Catalog1));
In this case, a value of NULL is returned since we used an empty return statement, as var_dump makes clear.
New iterable type
The iterable is a new compound type in PHP 7.1. Pseudo types are keywords used for types or values that an argument may have. The iterable type may be used as parameter type or return type. It accepts an array or an object that implements the Traversable interface, both of which can be iterated over using foreach.
First, we shall demonstrate how to use iterable with an array. Create a script iter.php in which declare a function with parameter type iterable. iterable type parameters may declare a default value that is NULL or an array. Within the function iterate over the iterable using foreach() and output its values. Create an array and invoke the function using the array as its argument. The iter.php is listed.
<?php $catalog = ['Oracle Magazine','Java Magazine','PHP Magazine']; function iterator(iterable $iter) { foreach ($iter as $val) { echo $val; echo "<br/>"; } } iterator($catalog); ?>
Run the script to output the array values:
Oracle Magazine
Java Magazine
PHP Magazine
An iterable also accepts a class object that implements the Traversable interface. To demonstrate this, create a script iter_traversable.php and declare a class that implements the IteratorAggregate interface, which further extends the Traversable interface. Declare three class properties.
public $journal1 = "Oracle Magazine"; public $journal2 = "Java Magazine"; public $journal3 = "PHP Magazine"
Add a class constructor that implements the interface function abstract public Traversable getIterator ( void ). Let’s call this class catalogData. In the same script, also declare a function with parameter type iterable. Within this function, use foreach to iterate over the iterable parameter and output its values:
function iterator(iterable $iter) { foreach($iter as $key => $value) { var_dump($key, $value); echo "\n"; } }
Finally, invoke the function with an instance of the class catalogData as an argument:
$obj = new catalogData; iterator($obj); The iter_traversable.php script is listed: <?php class catalogData implements IteratorAggregate { public $journal1 = "Oracle Magazine"; public $journal2 = "Java Magazine"; public $journal3 = "PHP Magazine"; public function __construct() { } public function getIterator() { return new ArrayIterator($this); } } $obj = new catalogData; function iterator(iterable $iter) { foreach($iter as $key => $value) { var_dump($key, $value); echo "\n"; } } iterator($obj); ?>
Now, run the script to output the key/value pairs in the iterable:
string(8) "journal1" string(15) "Oracle Magazine" string(8) "journal2" string(13) "Java Magazine" string(8) "journal3" string(12) "PHP Magazine"
The iterable type supports full contravariance (for parameter type) and covariance (for return type). Covariance and Contravariance are discussed in detail in an earlier article PHP 7 — Getting Started and OOP Improvements. Full contravariance implies that parameter types array and Traversable may be widened to iterable. Full covariance implies that return type iterable may be narrowed to array or Traversable. Next, we shall demonstrate covariance and contravariance with iterable using an example. Create a script iter_extend_ret_type.php and declare a class containing an iterator function with an array parameter and nullable iterable return type. Within the class, iterate over the array argument using foreach and output its values. Declare a class that extends the first one and overrides the iterator function with a function that has an iterable parameter and nullable array return type. Create an instance of the extending class and invoke its iterator function. The script is listed here:
<?php class ClassA{ function iterator(array $arr) : ?iterable { foreach ($arr as $val) { echo $val; echo "<br/>"; return null; } } } class ClassB extends ClassA{ function iterator(iterable $iter) : ?array { foreach ($iter as $val) { echo $val; echo "<br/>"; } return null; } } $catalog = ['Oracle Magazine','Java Magazine','PHP Magazine']; $classB=new ClassB(); $classB->iterator($catalog); ?>
Run the script, which will output:
Oracle Magazine
Java Magazine
PHP Magazine
Functions with return type iterable may also be used as generators. As an example, create a script iterable_gen.php and create and invoke a generator function with return type iterable. Yield some values in the generator function and return an array. Subsequently, output the values yielded by the generator function. Also output the generator function return value using getReturn() function to obtain the return value:
<?php function generator(): iterable { yield 'a'; yield 'b'; yield 'c'; return ['a','b','c']; } $gen = generator(); foreach ($gen as $value) { echo "$value\n"; } var_dump($gen->getReturn()); ?>
Run the script to output the values yielded by the generator function.
a b c array(3) { [0]=> string(1) "a" [1]=> string(1) "b" [2]=> string(1) "c" }
Typed Properties
Version 7 has made several improvements to PHP's type system. PHP 7.4 adds support for typed properties, using which you can declare types for class properties. Class properties do nor require you to explicitly declare getter/setter methods for them. Some of their salient characteristics are:
Types may be declared on static properties as well.
References to typed properties are supported.
The typed properties are affected by the strict_types directive just as the parameter types and return types are.
Types may be used with var notation.
Default values for typed properties may be declared.
The type of multiple properties may be declared in a single declaration.
Implicit int to float cast is made.
The type for a nullable property may be declared.
A class property of type callable or void cannot be declared.
As an example, consider the following class called Catalog that illustrates several of the preceding characteristics:
<?php declare(strict_types=1); class Catalog { public int $catalogid,$journalid; public ?string $journal=null; public static string $edition="January-February 2020"; var bool $flag; public float $f=1; public function __construct(int $catalogid,int $journalid,string $journal,bool $flag) { $this->catalogid = $catalogid; $this->journalid = $journalid; $this->journal = $journal; $this->flag = $flag; } } $c = new Catalog(123,345,"PHP Magazine",true); echo "Catalogid: ".$c->catalogid."\n"; echo "Journalid: ".$c->journalid."\n"; echo "Journal: ".$c->journal."\n"; echo "Flag: ".$c->flag."\n"; echo "Edition: ".Catalog::$edition."\n"; ?>
Run now the script, whose output is shown in Figure 2.

Figure 2. Output illustrating use of Typed properties
To demonstrate the use of properties along with strict-type mode, consider the following script that sets strict_types to 1 and declares a class property called $catalogid of type int. Then try to assign the $catalogid property a string value:
<?php declare(strict_types=1); class Catalog { public int $catalogid; } $c = new Catalog(); $c->catalogid = "123"; ?>
When the script is run, the following TypeError is thrown:
Uncaught TypeError: Typed property Catalog::$catalogid must be int, string used
If you define, no TypeError is thrown. The important distinction to note here is that the assigned value must satisfy the strict_types mode at the write-location of the property. In other terms, the strict_types mode at the property declaration location is not relevant. If strict_types mode is set to 1 at the write-location, the assigned value must be of the declared type. To demonstrate the use of different modes, we shall use two different files a.php and b.php with strict_types mode set to 1 and 0 respectively. The scripts also demonstrate the following characteristics of references when used with typed properties:
An uninitialized-nullable property may be accessed by reference
An uninitialized non-nullable property cannot be accessed by reference
An array may be accessed by reference.
In a.php, set strict_types mode to 1 and declare a class A containing a typed class property called $a of type int. Make sure the a.php script also declare an array, a nullable property and a non-nullable property:
<?php declare(strict_types=1); class A { public int $a; public array $array = [3, 1, 2]; public ?int $x; public int $y; }
In a second file, b.php, include a.php and set strict_types mode to 0. Instantiate class A, then use var_dump to output this instance’s $a property value, which is shown in the following listing after the comment //. Then, access the array type property through its reference, and finally, sort and output it.
Now access the int type variable $a through its reference and assign it string value “1”. Output the variable $a value using var_dump and you will see no TypeError is thrown. This is because th value stored in $a is cast to its type, int.
Also notice you can access the uninitialized nullable property $x through its reference. In such a case, it will be transparently initialized to NULL. On the contrary, if you try to access the uninitialized non-nullable property $y, you will get a TypeError.
<?php declare(strict_types=0); include 'a.php'; $a = new A; $a->a = "1"; var_dump($a->a); // int(1) sort($a->array); var_dump($a->array);// array(3) { [0]=> int(1) [1]=> //int(2) [2]=> int(3) } $x =& $a->x; // Initialized to null $y =& $a->y; //TypeError Uncaught Error: Cannot access //uninitialized non-nullable property A::$y by reference
Next, we shall discuss another important characteristic of typed properties that has to do with type invariance.
The type of a non-private property cannot be changed in a derived class. A non-private property type cannot be added or removed either.
The type of a private property can be changed in a derived class. Private property types may be added or removed.
To demonstrate type invariance, declare a class called A that contains a private variable $a of type int, a public variable $b of type string, a nullable public variable $c of type int, and a public variable $d of type string. Also declare a void type property called $v to verify the void type cannot be used with properties.
<?php class A { private int $a; public string $b; public ?int $c; public string $d; public void $v;//Property A::$v cannot have type void }
Declare now a class B that extends class A and changes the types of its class properties. Change the type of the private property $a from int to string and make it public, which is supported. If you try to change the type of the public property $b from string to int; the type of the public property $c nullable int to int; or to omit the type of the public property $d, you will get errors. The error messages output are shown below as comments.
class B extends A { public string $a; public int $b; // Type of B::$b must be string (as in class A) public int $c; // Type of B::$c must be ?int (as in class A) public $d; // Type of B::$d must be string (as in class A) }
Summary
In this third article in our series on PHP 7.x, we discussed new features in PHP’s type system.
PHP 7.0 added support for scalar type declarations for string,int,float, and bool types. PHP also 7.0 added support for return type declarations to be used in the return statement.
PHP 7.1 added support for the null type, which has only one value, NULL, and for a return type called void, representing the absence of any value. PHP 7.1 also added support for a new type called iterable. While the void type may be used only as return type, iterable can be used as a parameter or a return type.
Typed properties were added in PHP 7.4, which enable to explicitly declare types for class properties.
In the next article in the series we shall explore new features for PHP functions.
0 notes
Text
C++17
C++ language is constantly evolving, and for us, as for developers of a static analyzer, it is important to track all its changes, in order to support all new features of the language. In this review article, I would like to share with the reader the most interesting innovations introduced in C++17, and demonstrate them with examples.
Now, developers of compilers are actively adding support for the new standard. You can see what is supported at the moment via the following links:
GCC
Clang
Visual Studio
Fold expressions
I would like to start with a few words about what a fold is (also known as reduce or accumulate).
Fold is a function that applies the assigned combining function to sequential pairs of elements in a list, and returns a result. The simplest example is the summing up of elements in the list using a fold:
Example from C++:
std::vector<int> lst = { 1, 3, 5, 7 }; int res = std::accumulate(lst.begin(), lst.end(), 0, [](int a, int b) { return a + b; }); std::cout << res << '\n'; // 16
If the combining function is applied to the first item in a list and to the result of the recursive processing of the tail of a list, then the fold is called 'right'. In our example, we will get:
1 + (3 + (5 + (7 + 0)))
If the combining function is applied to the result of the recursive processing at the top of the list (the entire list without the last element) and to the last element, then a folding is called 'left'. In our example, we will get:
(((0 + 1) + 3) + 5) + 7
Thus, the fold type determines the order of evaluation.
In C++17 there is also folding support for a template parameters list. It has the following syntax:
op is one of the following binary operators:
+ - * / % ^ & | ~ = < > << >> += -= *= /= %= ^= &= |= <<= >>= == != <= >= && || , .* ->*
pack is an expression containing an undisclosed parameter pack
init - initial value
For example, here's a template function that takes a variable number of parameters and calculates their sum:
// C++17 #include <iostream> template<typename... Args> auto Sum(Args... args) { return (args + ...); } int main() { std::cout << Sum(1, 2, 3, 4, 5) << '\n'; // 15 return 0; }
Note: In this example, the Sum function could be also declared as constexpr.
If we want to specify an initial value, we can use binary fold:
// C++17 #include <iostream> template<typename... Args> auto Func(Args... args) { return (args + ... + 100); } int main() { std::cout << Func(1, 2, 3, 4, 5) << '\n'; //115 return 0; }
Before C++17, to implement a similar function, you would have to explicitly specify the rules for recursion:
// C++14 #include <iostream> auto Sum() { return 0; } template<typename Arg, typename... Args> auto Sum(Arg first, Args... rest) { return first + Sum(rest...); } int main() { std::cout << Sum(1, 2, 3, 4); // 10 return 0; }
It is worth highlighting the operator ',' (comma), which will expand the pack into a sequence of actions separated by commas. Example:
// C++17 #include <iostream> template<typename T, typename... Args> void PushToVector(std::vector<T>& v, Args&&... args) { (v.push_back(std::forward<Args>(args)), ...); //This code is expanded into a sequence of expressions //separated by commas as follows: //v.push_back(std::forward<Args_1>(arg1)), //v.push_back(std::forward<Args_2>(arg2)), //.... } int main() { std::vector<int> vct; PushToVector(vct, 1, 4, 5, 8); return 0; }
Thus, folding greatly simplifies work with variadic templates.
Read more - https://www.viva64.com/en/b/0533/
15 notes
·
View notes
Text
Prominent Blockchain Programming Languages to consider while building Blockchain Apps!

Blockchain has become a buzzword in today’s tech world. This technology has successfully resolved the traditional roadblocks existent in certain industrial domains by decentralizing dataand opening up new avenues of security and transparency.
Blockchain records digital information ina manner that the information can be recorded and distributed, but not altered. Hence, Blockchain is used to form immutable ledgers and records or transactions that cannot be hacked, modified, or destroyed. Blockchain applications are employed for demanding tasks like the exchange of cryptocurrencies, the secure sharing of medical data, voting mechanism, NFT marketplaces, making/receiving cross-border payments, monitoring supply chain/logistics, and many more.
However, developing such solutions is not an easy task, and businesses planning to adopt Blockchain systems must be aware of the ins and outs of Blockchain development. One of the crucial considerations for creating Blockchain solutions is the programming language stack chosen for development. And, needless to say, the programming language should be chosen as per the project requirements. This post explores the offerings of the top Blockchain programming languages with examples of use cases. The write-up will provide a clear idea and help you to pick the most suitable language stack for your upcoming Blockchain project.
Blockchain Functioning: In a Nutshell
The Blockchain system comprises a digital ledger of transactions. Each block within the chain contains a certain number of transactions and whenever a new transaction takes place on the blockchain network, the transaction record is added to each participant’s ledger. This decentralized database is called DLT (Distributed Ledger Technology) and is managed by multiple participants.
Top Blockchain Programming Languages

Solidity
Solidity was created by the Ethereum team in 2014 for writing Ethereum-based smart contracts, to enhance the usability of Blockchain solutions. With Solidity, developers were able to write a high-level code that is smart-contract oriented and that could be translated into the usable lower-level languages prevalent at that time.The language resembles the ECMAScript syntax but contains features such as static typing, variadic return types, and so on. And hence, it is one of the mostpreferred programming languages used for Blockchain projects and recommended by mostBlockchain app developersaround the world.
This statically typed Blockchain language offers a stable and flexible coding pattern for smart contracts and provides an accurate as well as a safe medium where different sources can frame smart contracts between parties. Moreover, it is a flexible and user-friendly language that comes with ABI (Application Binary Interface) that provides several type-safe functions. Developers can effortlessly acquire the necessary skills needed to use Solidity, whether they are experienced ones or simply beginners.
Blockchain Project Use Cases: Ethereum, Chainlink, Sushiswap, and Compound Protocol.
C++
This object-oriented language is one of the key Blockchain programming languages. C++ was created to code the decentralized cryptocurrency system and developers employed it to code bitcoins. But today, it suits the purpose of other Blockchain-based projectsand has been used for storing transaction information in cryptocurrencies like Ripple’s XRP Ledger, Ethereum’s smart contracts, etc.
C++ is easy to use and flexible; and comes with abilities like advanced multi-threading, primitive control over memory, and an efficient CPU management capability. It enables one to isolate the code for various data structures and allows you to move semantics so that data can be copied effectively. C++ users can control the code as desired – they can choose between providing full access to the code or allowing access to only certain aspects as per the need. With C++, one can easily manipulate blocks and chains, and so, is an ideal pick for scenarios where one needs to fully control their system resources.
Blockchain Project Use Cases:Monero, Ripple, Stellar, EOS, Litecoin.
Python
Python is one of the most popular programming languages used for architecting Blockchain applications, crypto exchange, and smart contracts. It is a robust, versatile, and object-oriented programming language that comes with open-source support and also, several frameworks and libraries such as Numba that accelerate the development without affecting the performance or security. Python dynamically supports OOP, and hence, facilitates crafting solutions in Blockchain as well as in Machine Learning and Artificial Intelligence. Using this language, one can easily detect errors and debug those errors.
Python is particularly helpful for newbie developers working on Blockchain projects as this language facilitates building prototypes quickly without having to write lengthy codes and the developers have the option of selecting from a wide range of plugins, libraries, and online resources.
Python, being an interpreted language creates roadblocks when complicated cryptographic operations are involved, but this problem can be resolved by the proficiency of experienced Blockchain app developers.
Blockchain Project Use Cases: Steemit, Ethereum, Hyperledger Fabric, NEO, etc.
GoLang
GoLang, a statically typed, compiled and multi-threaded language created by Google, is one of the most popular Blockchain programming languages in the NFT marketplace. The language integrates the best of both worlds – the ease of developing the code and the effectiveness of compiled language. It combines the features of Java, Python, and C++ and is being used by the Hyperledger Fabric platform currently. It is user-friendly, fast, flexible, and scalable.
Using GoLang, one can run several processes simultaneously, and therefore, it is can effectively handle several parts of blockchain simultaneously. GoLang is not only speedy but also offers accessible maintenance features and so, it’s an ideal pick when a decentralized app is being distributed on Ethereum’s network. However, it comes with a difficult learning curve but will be simple for C++ developers.
Blockchain Project Use Cases: Ethereum, Loom Network, Hyperledger Fabric, GoChain, and Dero.
Java
Java is an object-oriented programming language that follows a “write once and follow everywhere” approach and so, enables one to write codes that are highly portable. With the Java Virtual Machine (JVM), developers can run their codes on any system or platform. And, as the universal JVM is used for execution, Java programs need not depend on a system-specific architecture. This portability of Java facilitates the creation of easy-going and immutable blockchains. Furthermore, Java comes with an abundant API (Application Programming Interface) that contains several Java classes, interfaces, packages, etc. This property helps in building apps without any need to know their internal implementations.
Java offers a simple and extensible plugin architecture that helps to create a flexible Blockchain solution. Java has a huge and dynamic community that provides prompt and effective solutions to developers whenever they encounter any issue.
Blockchain Project Use Cases: IOTA, NEO, NEM, Ethereum, Fabric, and Hyperledger.
C#
C# is an open-source programming language coined by Microsoft and enjoys humongous popularity worldwide. It employs easy Object-Oriented and Extensible Markup methods, without the developer’s help. Its rich library class simplifies the use of menu functions and implements them for coding. The assembly feature eases out handling the issue of version control. With C#, open-source developers can effortlessly write codes that are highly portable and run across several OS like Mac, Linux, Android, and Windows.
Blockchain Project Use Cases: IOTA, NEO, Blockchain as a Service, and Stratis.
Rholang
Rholang is employed for creating smart contracts and high-grade Blockchain projects. It follows a functional approach – at first, it examines the application through several functions and thereafter, solves them as per the sequence. It is secure, reliable, easytouse, and speedy.
LLL (Low-Level-Lisp-like language)
Low-Level-Lisp-like language, commonly known as LLL, is a low-level programming language. LLL happens to be quite easy-going and minimalistic, it’s just a small-sized wrapper directly placed over the EVM coding. This is one of the original Ethereum programming languages used for smart contracts. It offers a different programming discipline and point of view as compared to the universal Solidity language.
To make it compatible with EVM programming, the Lisp-like code contains a thin layer of parentheses. So, the LLL users enjoy high-end programming support while accessing various lower-level sources of power as well as memory locations. Moreover, this language enables programmers to develop effective contracts that are smaller in size as compared to the ones created using higher-level languages.
Simplicity
This high-level Blockchain programming language was designed for smart contracts and it caters to professional programmers as well as open-source developers. This language is relatively new and reduces the low-level understanding and complicated functionality of the Bitcoin Script.
Simplicity helps Blockchain app developers to enhance productivity and avoid distractions. It hides low-level components from engineers and developers, resulting in a rapid development speed.
JavaScript
This popular programming language works for Blockchain development as well because of Node.js, a runtime environment of JavaScript. The language helps developers to handle asynchronous code which is the fundamental prerequisite in the Blockchain environment. Moreover, it enables asynchronous parallel programming due to which the Blockchain program can complete more than one action simultaneously.
Vyper
This Blockchain programming language is derived from Python3, although it doesn’t contain all the Python features in it. It was designed as an alternative for the language Solidity and is primarily employed in EVM (Ethereum Virtual Machine). However, Vyper’s control structures are different fromthe ones in Solidity and it handles security issues differently as well. Vyper’s control structure is distinct and contains features such as modifiers, recursive calling, infinite loops, etc.
Obsidian
Obsidian is one of the newer Blockchain programming languages. It presently functions on the Hyperledger Fabric platform and the Ethereum Blockchain platform.
Most blockchain programs are organized around a machine having a high-level state and Obsidian’s state-oriented programming helps one to explicitly declare and transition amongst states. Obsidian builds a flowchart-like sequence that helps one to view contracts through different stages. The states and transitions within the states have to be mentioned while coding.
Obsidian offers a linear type system that simplifies the process ofimplementing a belt to suspenders. The compiler can make full use of the types for avoiding bug issues or typo-based errors.
End Note
I hope the aforesaid information was beneficial and will help you in selecting the best-suited programming language for building Blockchain solutions. Coming to Blockchain development, it’s a challenging task and has to be executed properly for obtaining the best results. Moreover, creating a Blockchain network is not enough, the system needs to be managed and maintained properly. So, in most cases, entrepreneurs seek professional help.
For professional assistance in developing and maintaining Blockchain solutions, the transformative Blockchain app development services offered byBiz4Solutions, is worth a try! We have the experience and expertise to cater to the Blockchain development needs of global clients with diverse requirements.
To know more about our core technologies, refer to links below:
Swift App development
Java App Development
.Net App Development
0 notes
Link
(Via: Hacker News)
Metaprogramming, or the ability to inspect, modify and generate code at compile-time (as opposed to reflection, which is runtime introspection of code), has slowly been gaining momentum. Programmers are finally admitting that, after accidentally inventing turing complete template systems, maybe we should just have proper first-class support for generating code. Rust has macros, Zig has built-in compile time expressions, Nim lets you rewrite the AST however you please, and dependent types have been cropping up all over the place. However, with great power comes great responsibility undecidable type systems, whose undefined behavior may involve summoning eldritch abominations from the Black Abyss of Rěgne Ūt.
One particular place where metaprogramming is particularly useful is low-level, high-performance code, which is what Terra was created for. The idea behind Terra is that, instead of crafting ancient runes inscribed with infinitely nested variadic templates, just replace the whole thing with an actual turing-complete language, like say, Lua (technically including LuaJIT extensions for FFI). This all sounds nice, and no longer requires a circle of salt to ward off demonic syntax, which Terra is quick to point out. They espouse the magical wonders of replacing your metaprogramming system with an actual scripting language:
In Terra, we just gave in to the trend of making the meta-language of C/C++ more powerful and replaced it with a real programming language, Lua.
The combination of a low-level language meta-programmed by a high-level scripting language allows many behaviors that are not possible in other systems. Unlike C/C++, Terra code can be JIT-compiled and run interleaved with Lua evaluation, making it easy to write software libraries that depend on runtime code generation.
Features of other languages such as conditional compilation and templating simply fall out of the combination of using Lua to meta-program Terra
Terra even claims you can implement Java-like OOP inheritance models as libraries and drop them into your program. It may also cure cancer (the instructions were unclear).
As shown in the templating example, Terra allows you to define methods on struct types but does not provide any built-in mechanism for inheritance or polymorphism. Instead, normal class systems can be written as libraries. More information is available in our PLDI Paper.
The file lib/javalike.t has one possible implementation of a Java-like class system, while the file lib/golike.t is more similar to Google’s Go language.
I am here to warn you, traveler, that Terra sits on a throne of lies. I was foolish. I was taken in by their audacious claims and fake jewels. It is only when I finally sat down to dine with them that I realized I was surrounded by nothing but cheap plastic and slightly burnt toast.
The Bracket Syntax Problem
Terra exists as a syntax extension to Lua. This means it adds additional keywords on top of Lua’s existing grammar. Most languages, when extending a syntax, would go to great lengths to ensure the new grammar does not create any ambiguities or otherwise interfere with the original syntax, treating it like a delicate flower that mustn’t be disturbed, lest it lose a single petal.
Terra takes the flower, gently places it on the ground, and then stomps on it, repeatedly, until the flower is nothing but a pile of rubbish, as dead as the dirt it grew from. Then it sets the remains of the flower on fire, collects the ashes that once knew beauty, drives to a nearby cliffside, and throws them into the uncaring ocean. It probably took a piss too, but I can’t prove that.
To understand why, one must understand what the escape operator is. It allows you to splice an abstract AST generated from a Lua expression directly into Terra code. Here is an example from Terra’s website:
function get5() return 5 end terra foobar() return [ get5() + 1 ] end foobar:printpretty() > output: > foobar0 = terra() : {int32} > return 6 > end
But, wait, that means it’s… the same as the array indexing operator? You don’t mean you just put it inside like–
local rest = {symbol(int),symbol(int)} terra doit(first : int, [rest]) return first + [rest[1]] + [rest[2]] end
What.
WHAT?!
You were supposed to banish the syntax demons, not join them! This abomination is an insult to Nine Kingdoms of Asgard! It is the very foundation that Satan himself would use to unleash Evil upon the world. Behold, mortals, for I come as the harbinger of despair:
function idx(x) return `x end function gen(a, b) return `array(a, b) end terra test() -- Intended to evaluate to array(1, 2) 0 return [gen(1, 2)][idx(0)] end
For those of you joining us (probably because you heard a blood-curdling scream from down the hall), this syntax is exactly as ambiguous as you might think. Is it two splice statements put next to each other, or is a splice statement with an array index? You no longer know if a splice operator is supposed to index the array or act as a splice operator, as mentioned in this issue. Terra “resolves this” by just assuming that any two bracketed expressions put next to each other are always an array indexing operation, which is a lot like fixing your server overheating issue by running the fire suppression system all day. However, because this is Lua, whose syntax is very much like a delicate flower that cannot be disturbed, a much worse ambiguity comes up when we try to fix this.
function idx(x) return `x end function gen(a, b) return `array(a, b) end terra test() -- This is required to make it evaluate to array(1,2)[0] -- return [gen(1, 2)][ [idx(0)] ] -- This doesn't work: return [gen(1, 2)][[idx(0)]] -- This is equivalent to: -- return [gen(1, 2)] "idx(0)" end
We want to use a spliced Lua expression as the array index, but if we don’t use any spaces, it turns into a string because [[string]] is the Lua syntax for an unescaped string! Now, those of you who still possess functioning brains may believe that this would always result in a syntax error, as we have now placed a string next to a variable. Not so! Lua, in it’s infinite wisdom, converts anything of the form symbol"string" or symbol[[string]] into a function call with the string as the only parameter. That means that, in certain circumstances, we literally attempt to call our variable as a function with our expression as a string:
local lookups = {x = 0, y = 1, z = 2, w = 3 }; vec.metamethods.__entrymissing = macro(function(entryname, expr) if lookups[entryname] then -- This doesn't work return `expr.v[[lookups[entryname]]] -- This is equivalent to -- return `expr.v "lookups[entryname]" -- But it doesn't result in a syntax error, becase it's equivalent to: -- return `extr.v("lookups[entryname]") else error "That is not a valid field." end end)
As a result, you get a type error, not a syntax error, and a very bizarre one too, because it’s going to complain that v isn’t a function. This is like trying to bake pancakes for breakfast and accidentally going scuba diving instead. It’s not a sequence of events that should ever be related in any universe that obeys causality.
It should be noted that, after a friend of mine heard my screams of agony, an issue was raised to change the syntax to a summoning ritual that involves less self-mutilation. Unfortunately, this is a breaking change, and will probably require an exorcism.
The Documentation Is Wrong
Terra’s documentation is so wrong that it somehow manages to be wrong in both directions. That is, some of the documentation is out-of-date, while some of it refers to concepts that never made it into master. I can only assume that a time-traveling gremlin was hired to write the documentation, who promptly got lost amidst the diverging timelines. It is a quantum document, both right and wrong at the same time, yet somehow always useless, a puzzle beyond the grasp of modern physics.
The first thing talked about in the API Reference is a List object. It does not actually exist. A primitive incarnation of it does exist, but it only implements map() and insertall(). Almost the entire section is completely wrong for the 1.0.0-beta1 release. The actual List object being described sits alone and forgotten in the develop branch, dust already beginning to collect on it’s API calls, despite those API calls being the ones in the documentation… somehow.
:printpretty() is a function that prints out a pretty string representation of a given piece of Terra code, by parsing the AST representation. On it’s face, it does do exactly what is advertised: it prints a string. However, one might assume that it returns the string, or otherwise allows you to do something with it. This doesn’t happen. It literally calls the print() function, throwing the string out the window and straight into the stdout buffer without a care in the world. If you want the actual string, you must call either layoutstring() (for types) or prettystring() (for quotes). Neither function is documented, anywhere.
Macros can only be called from inside Terra code. Unless you give the constructor two parameters, where the second parameter is a function called from inside a Lua context. This behavior is not mentioned in any documentation, anywhere, which makes it even more confusing when someone defines a macro as macro(myfunction, myfunction) and then calls it from a Lua context, which, according to the documentation, should be impossible.
Struct fields are not specified by their name, but rather just held in a numbered list of {name, type} pairs. This is documented, but a consequence of this system is not: Struct field names do not have to be unique. They can all be the same thing. Terra doesn’t actually care. You can’t actually be sure that any given field name lookup will result in, y’know, one field. Nothing mentions this.
The documentation for saveobj is a special kind of infuriating, because everything is technically correct, yet it does not give you any examples and instead simply lists a function with 2 arguments and 4 interwoven optional arguments. In reality it’s absolutely trivial to use because you can ignore almost all the parameters. Just write terralib.saveobj("blah", {main = main}) and you’re done. But there isn’t a single example of this anywhere on the entire website. Only a paragraph and two sentences explaining in the briefest way possible how to use the function, followed by a highly technical example of how to initialize a custom target parameter, which doesn’t actually compile because it has errant semicolons. This is literally the most important function in the entire language, because it’s what actually compiles an executable!
The defer keyword is critical to being able to do proper error cleanup, because it functions similar to Go’s defer by performing a function call at the end of a lexical scope. It is not documented, anywhere, or even mentioned at all on the website. How Terra manages to implement new functionality it forgets to document while, at the same time, documenting functionality that doesn’t exist yet is a 4-dimensional puzzle fit for an extra-dimensional hyperintelligent race of aliens particularly fond of BDSM.
You’d think that compiling Terra on Linux would be a lot simpler, but you’d be wrong. Not only are the makefiles unreliable, but cmake itself doesn’t seem to work with LLVM 7 unless you pass in a very specific set of flags, none of which are documented, because compiling via cmake isn’t documented at all, and this is the only way to compile with LLVM 7 or above on the latest Ubuntu release!
Perhaps there are more tragedies hidden inside this baleful document, but I cannot know, as I have yet to unearth the true depths of the madness lurking within. I am, at most, on the third or fourth circle of hell.
Terra Doesn’t Actually Work On Windows
Saying that Terra supports Windows is a statement fraught with danger. It is a statement so full of holes that an entire screen door could try to sell you car insurance and it’d still be a safer bet than running Terra on Windows. Attempting to use Terra on Windows will work if you have Visual Studio 2015 installed. It might work if you have Visual Studio 2013 installed. No other scenarios are supported, especially not ones that involve being productive. Actually compiling Terra on Windows is a hellish endeavor comparable to climbing Mount Everest in a bathing suit, which requires either having Visual Studio 2015 installed to the default location, or manually modifying a Makefile with the exact absolute paths of all the relevant dependencies. At least up until last week, when I submitted a pull request to minimize the amount of mountain climbing required.
The problem Terra runs into is that it tries to use a registry value to find the location of Visual Studio and then work out where link.exe is from there, then finds the include directories for the C runtime. This hasn’t worked since Visual Studio 2017 and also requires custom handling for each version because compiling an iteration of Visual Studio apparently involves throwing the directory structure into the air, watching it land on the floor in a disorganized mess, and drawing lines between vaguely related concepts. Good for divining the true nature of the C library, bad for building directory structures. Unfortunately, should you somehow manage to compile Terra, it will abruptly stop working the moment you try to call printf, claiming that printf does not actually exist, even after importing stdio.h.
Many Terra tests assume that printf actually resolves to a concrete symbol. This is not true and hasn’t been true since Visual Studio 2015, which turned several stdio.h functions into inline-only implementations. In general, the C standard library is under no obligation to produce an actual concrete symbol for any function - or to make sense to a mere mortal, for that matter. In fact, it might be more productive to assume that the C standard was wrought from the unholy, broiling chaos of the void by Cthulhu himself, who saw fit to punish any being foolish enough to make reasonable assumptions about how C works.
Unfortunately, importing stdio.h does not fix this problem, for two reasons. One, Terra did not understand inline functions on Windows. They were ephemeral wisps, vanishing like a mote of dust on the wind the moment a C module was optimized. A pull request fixed this, but it can’t fix the fact that the Windows SDK was wrought from the innocent blood of a thousand vivisected COMDAT objects. Microsoft’s version of stdio.h can only be described as an extra-dimensional object, a meta-stable fragment of a past universe that can only be seen in brief slivers, never all at once.
Luckily for the Terra project, I am the demonic presence they need, for I was once a Microsoftie. Long ago, I walked the halls of the Operating Systems Group and helped craft black magic to sate the monster’s unending hunger. I saw True Evil blossom in those dark rooms, like having only three flavors of sparkling water and a pasta station only open on Tuesdays.
I know the words of Black Speech that must be spoken to reveal the true nature of Windows. I know how to bend the rules of our prison, to craft a mighty workspace from the bowels within. After fixing the cmake implementation to function correctly on Windows, I intend to perform the unholy incantations required to invoke the almighty powers of COM, so that it may find on which fifth-dimensional hyperplane Visual Studio exists. Only then can I disassociate myself from the mortal plane for long enough to tackle the stdio.h problem. You see, children, programming for Windows is easy! All you have to do is s͏̷E͏l͏̢҉l̷ ̸̕͡Y͏o҉u͝R̨͘ ̶͝sơ̷͟Ul̴
For those of you who actually wish to try Terra, but don’t want to wait for me to fix everything a new release, you can embed the following code at the top of your root Terra script:
if os.getenv("VCINSTALLDIR") ~= nil then terralib.vshome = os.getenv("VCToolsInstallDir") if not terralib.vshome then terralib.vshome = os.getenv("VCINSTALLDIR") terralib.vclinker = terralib.vshome..[[BIN\x86_amd64\link.exe]] else terralib.vclinker = ([[%sbin\Host%s\%s\link.exe]]):format(terralib.vshome, os.getenv("VSCMD_ARG_HOST_ARCH"), os.getenv("VSCMD_ARG_TGT_ARCH")) end terralib.includepath = os.getenv("INCLUDE") function terralib.getvclinker() local vclib = os.getenv("LIB") local vcpath = terralib.vcpath or os.getenv("Path") vclib,vcpath = "LIB="..vclib,"Path="..vcpath return terralib.vclinker,vclib,vcpath end end
Yes, we are literally overwriting parts of the compiler itself, at runtime, from our script. Welcome to Lua! Enjoy your stay, and don’t let the fact that any script you run could completely rewrite the compiler keep you up at night!
The Existential Horror of Terra Symbols
Symbols are one of the most slippery concepts introduced in Terra, despite their relative simplicity. When encountering a Terra Symbol, one usually finds it in a function that looks like this:
TkImpl.generate = function(skip, finish) return quote if [TkImpl.selfsym].count == 0 then goto [finish] end [TkImpl.selfsym].count = [TkImpl.selfsym].count - 1 [stype.generate(skip, finish)] end end
Where selfsym is a symbol that was set elsewhere.
“Aha!” says our observant student, “a reference to a variable from an outside context!” This construct does let you access a variable from another area of the same function, and using it to accomplish that will generally work as you expect, but what it’s actually doing is much worse more subtle. You see, grasshopper, a symbol is not a reference to a variable node in the AST, it is a reference to an identifier.
local sym = symbol(int) local inc = quote [sym] = [sym] + 1 end terra foo() var [sym] = 0 inc inc return [sym] end terra bar() var[sym] = 0 inc inc inc return [sym] end
Yes, that is valid Terra, and yes, the people who built this language did this on purpose. Why any human being still capable of love would ever design such a catastrophe is simply beyond me. Each symbol literally represents not a reference to a variable, but a unique variable name that will refer to any variable that has been initialized in the current Terra scope with that particular identifier. You aren’t passing around variable references, you’re passing around variable names.
These aren’t just symbols, they’re typed preprocessor macros. They are literally C preprocessor macros, capable of causing just as much woe and suffering as one, except that they are typed and they can’t redefine existing terms. This is, admittedly, slightly better than a normal C macro. However, seeing as there have been entire books written about humanity’s collective hatred of C macros, this is equivalent to being a slightly more usable programming language than Brainfuck. This is such a low bar it’s probably buried somewhere in the Mariana Trench.
Terra is C but the Preprocessor is Lua
You realize now, the monstrosity we have unleashed upon the world? The sin Terra has committed now lies naked before us.
Terra is C if you replaced the preprocessor with Lua.
Remember how Terra says you can implement Java-like and Go-like class systems? You can’t. Or rather, you will end up with a pathetic imitation, a facsimile of a real class system, striped down to the bone and bereft of any useful mechanisms. It is nothing more than an implementation of vtables, just like you would make in C. Because Terra is C. It’s metaprogrammable C.
There can be no constructors, or destructors, or automatic initialization, or any sort of borrow checking analysis, because Terra has no scoping mechanisms. The only thing it provides is defer, which only operates inside Lua lexical blocks (do and end)… sometimes, if you get lucky. The exact behavior is a bit confusing, and of course can only be divined by random experimentation because it isn’t documented anywhere! Terra’s only saving grace, the singular keyword that allows you to attempt to build some sort of pretend object system, isn’t actually mentioned anywhere.
Of course, Terra’s metaprogramming is turing complete, and it is technically possible to implement some of these mechanisms, but only if you either wrap absolutely every single variable declaration in a function, or you introspect the AST and annotate every single variable with initialization statuses and then run a metaprogram over it to figure out when constructors or destructors or assignment operators need to be called. Except, this might not work, because the (undocumented, of course) __update metamethod that is supposed to trigger when you assign something to a variable has a bug where it’s not always called in all situations. This turns catching assignments and finding the l-value or r-value status from a mind-bogglingly difficult, herculean task, to a near-impossible trial of cosmic proportions that probably requires the help of at least two Avengers.
There Is No Type System
If Terra was actually trying to build a metaprogramming equivalent to templates, it would have an actual type system. These languages already exist - Idris, Omega, F*, Ada, Sage, etc. but none of them are interested in using their dependent type systems to actually metaprogram low-level code (although F* can produce it). The problem is that building a recursively metaprogrammable type system requires building a proof assistant, and everyone is so proud of the fact they built a proof assistant they forget that dependent type systems can do other things too, like build really fast memcpy implementations.
Terra, on the other hand, provides only the briefest glimpse of a type system. Terra functions enjoy what is essentially a slightly more complex C type system. However, the higher-level Lua context is, well, Lua, which has five basic types: Tables, Functions, Strings, Booleans and Numbers (it also has Thread, Nil, Userdata and CData for certain edge cases). That’s it. Also, it’s dynamic, not static, so everything is a syntax or a runtime error, because it’s a scripting language. This means all your metaprogramming is sprinkled with type-verification calls like :istype() or :isstruct(), except the top came off the shaker and now the entire program is just sprinkles, everywhere. This is fine for when your metaprograms are, themselves, relatively simple. It is not fine when you are returning meta-programs out of meta-meta-functions.
This is the impasse I find myself at, and it is the answer to the question I know everyone wants to know the answer to. For the love of heaven and earth and all that lies between, why am I still using Terra?
The truth is that the project I’m working on requires highly complex metaprogramming techniques in order to properly generate type-safe mappings for arbitrary data structures. Explaining why would be an entire blog post on it’s own, but suffice to say, it’s a complex user interface library that’s intended to run on tiny embedded devices, which means I can’t simply give up and use Idris, or indeed anything that involves garbage collection.
What I really want is a low-level, recursively metaprogrammable language that is also recursively type-safe, in that any type strata can safely manipulate the code of any layer beneath it, preferably via algebriac subtyping that ensures all types are recursively a subset of types that contain them, ad nauseam. This would then allow you to move from a “low-level” language to a “high-level” language by simply walking up the tower of abstraction, building meta-meta-programs that manipulate meta-programs that generate low-level programs.
Alas, such beauty can only exist in the minds of mathematicians and small kittens. While I may one day attempt to build such a language, it will be nothing more than a poor imitation, forever striving for an ideal it cannot reach, cursed with a vision from the gods of a pristine language no mortal can ever possess.
I wish to forge galaxies, to wield the power of computation and sail the cosmos upon an infinite wave of creativity. Instead, I spend untold hours toiling inside LLVM, wondering why it won’t print “Hello World”.
In conclusion, everything is terrible and the universe is on fire.
0 notes