I'm curious as to if it's feasible to syncretise these two aspects of variable evaluation into a shared feature that makes async and sync code feel alike.
That's how Haskell works. Everything is lazily evaluated, and in the case that evaluation is needed now, the "seq" function obtains it (https://wiki.haskell.org/Seq).
#DEFINE NOT_NULL(x) (bool)x
#DEFINE NOT_SPACE(x) ( ' ' != *x )
// ...
if ( NOT_NULL(v) && NOT_SPACE(v) ) { ... }The reason is mainly the many language construct of C++ cover most traditional use cases of macros when programming C while at the same time being much less error prone than macros.
A sibling show how one easily can achieve the very same thing using short lambdas instead. That variant is also bound to the scope one is currently in, and in order to have that safety with a macro one would need to undefine the macros afterwards. One would also need to check that they are not yet defined beforehand, and if so restore the previous macro afterwards in order to not break completely unrelated code in case of macro name clashes.
Define your booleans as functions of no args. A sample in Python:
var = 'abc'
var_contains_a = lambda: 'a' in var
var_shorter_than_5 = lambda: len(var) < 5
if var_contains_a() and var_shorter_than_5():
print(var)Taking the last top-level statement, the `if`:
if var_contains_a() and var_shorter_than_5: #note the lack of parens for the second
print(var)
This will print a string of any length that contains 'a' (or any other collection that implements `in` and does, in fact, contain an element, 'a'). The second function is passed directly as a boolean expression, and being a function, it resolves to true. auto not_null = [&]{ return (bool)p; };
auto not_space = [&]{ return (*p != ' '); };
if (not_null() && not_space()) {
It's not quite as ergonomic but it works.As an aside. I was curious if the compiler will optimize in the short circuit even if you extract the eagerly evaluated named booleans. However I was pretty sure the rules of c++ are against you and tests show this to be the case
But if you simulate the alias keyword with lambdas then the result after optimization are the same
It will optimize, but not necessarily what you wanted... Because null dereference is UB (with default compiler flags), it's allowed to elide null check.
Would be also nice to have this:
`foo` only evaluates once.