Skip to content

Discussion: Optional declarations and syntax sugar #27

Closed
@tatewake

Description

@tatewake

So based on what I understand about cppfront and Cpp2 as it stands, there's a union keyword that effectively infers / uses an std::variant wherever it's used, and it's invisible to the end-user-- I think that's great and a good choice.

However, it looks like when using optionals, you still have to declare them with the original C++ syntax… I think there's a missed opportunity here that has been well treaded in C# (via "Nullables"), JavaScript / TypeScript, and Swift.

If you look at Swift's Optionals, we have declaration like this:

var a: Int	// int type
var b: Int?	// Optional Int type
var c: Dog?	// Optional class type

And accessing values are like this (the last two lines are called "optional chaining" in most languages):

print(b ?? 7)		// prints the value of "b" if non-optional, otherwise prints "7"
let h = c?.height	// accessing member variables from an optional class
c?.bark()		// calls "bark" method on c if c is not null, does nothing otherwise
d?.data?.dog?.bark()	// Similar to above, but you have a hierarchy of optional members

Swift also provides the concept of "unwrapping" an optional; I don't want to muck up the above with this, but it would be negligent of me not to mention it:

if var c = c {	// try to "unwrap" the optional into a non-optional type
	c.bark()	// optional was successfully "unwrapped", c is now a non-optional type, and "bark" method can be called
}

In my opinion, Swift is a very "Optional first" type of language, meaning you often want to see if something "can be" an optional before you even consider a non-optional type, and I think this kind of thinking might also benefit C++… and maybe a good vector to do this would be through Cpp2 / cppfront.

If for nothing else the syntax sugar of using a declaration of type? to imply std::optional<type> and providing support for optional chaining (the c?.bark() instead of writing if (*c) { c->bark(); } would be tremendous in my opinion.

One other thing to consider about Optionals in general (as well as how they currently stand in Cpp2), is that the absence of a value is typically represented as null or nil or (in the case of C++)nullopt. I do agree (and totally support) the idea of eliminating NULL in Cpp2, but I think they track you'll find here is similar to Swift, where nil (their version of null) only exists to support the "absense of a value in an optional."

Whether or not you wanted to go down a similar "unwrap" path would be up to you (and dependent on if you even wanted to go down this "syntax sugar" idea or not), but I think there's lots to learn from other languages that do optionals that C++ can't do without considerable effort that are worth considering here.

tl;dr:

  • Consider treating optional types like you treat union -> std::variant
  • Learn from other languages (C#, TypeScript, Swift), and provide syntax sugar:
    • For declaration: b: Int?
    • For chaining: c?.bark()
    • For defaults: b ?? 5
  • Consider having a "null" but only for optional types (nullopt_t is okay, but maybe there's a better long-term naming solution)
  • Consider advanced ideas like optional unwrapping from Swift

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions