Skip to content

[SUGGESTION] Typed Expressions; generalized constructors, UDLs, unnamed variables and functions #463

@msadeqhe

Description

@msadeqhe

This is an alternative solution to this issue. If you don't like ...TYPE notation for object construction because of its UDL syntax, this is an alternative solution. In this suggestion, objection construction would use familiar notation EXPR:TYPE (aka Typed Expression) which is similar to how Cpp2 programmers use it within declarations.

Consider EXPR:TYPE as syntactic sugar to (: TYPE = EXPR). For example:

Abc: type;
Xyz: type;
func: (u: int) -> Abc;

a: int = 2;
b: = 2:int;       // (: int = 2)
c: = a:Abc;       // (: Abc = a)
d: = ():Abc;      // Default Constructor
e: = (a + b):Abc; // (: Abc = a + b)
r: = func(a):Abc; // (: Abc = func(a))
s: = func(2):Abc.start():Xyz.value; // Function Chaining
t: = a++:Abc;     // (: Abc = a++)
u: = a:Abc++;     // (: Abc = a)++
x: = 2:int:Abc;   // (: Abc =: int = 2) Constructor Chaining
y: = (2:int + 4:int):Abc; // (: Abc = (: int = 2) + (: int = 4))
z: = ("text", 2:int):Abc; // (: Abc = ("text", (: int = 2)))

Literally if x:int is at the start of a statement or function parameter, it would be a declaration, otherwise it would be a Typed Expression.

Abc: type;

// `x: Abc` is a parameter declaration.
func: (x: Abc) = {}

// `a: int` is a declaration.
a: int = 2;

// `a:Abc` is a Typed Expression, it calls the constructor of `Abc`.
m: = a:Abc;

EXPR:TYPE is similar to ...TYPE suggestion, except with the following advantages:

  • It's familiar and similar to declaration syntax in which types are specified in the language.
  • It's easier to parse, but ...TYPE would complicate the grammar especially for working within function chaining.
  • It doesn't need parentheses for simple expressions with unary postfix operators (e.g. a++:Abc). It depends on operator precedence, and it's left to right.

And this notation has the following disadvantages:

  • It requires an extra :. BTW it's opinion based.

I have to explain : within SOMETHING:TYPE is for object construction (as an expression) or declaration (as a statement), but :: within SOMETHING::TYPE is scope resulotion operator for qualified names. They can be combined like 10++ : my::Type. Also after the object is constructored, we can use operator dot or operator() or operator[] or ... to access members from it, e.g. 10:Type.call() or 10:Type[0].

Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?

No.

Will your feature suggestion automate or eliminate X% of current C++ guidance literature?

Yes.

  1. It unifies constructors with UDLs. They are semantically the same. Both of them create a new object.
    1. It's useful in generic programming.
    2. It reduces concept count.
      • Novice programmers don't need to learn a distinct concept about UDLs.
      • All types benefit from UDL like syntax. It's not needed to declare UDL for them.
      • It eliminates the need of understanding and learning built-in prefixes and suffixes for literals.
    3. The syntax of calling constructors will be expressive and readable.
  2. It distincts constructors from regular function calls. They are semantically different.
    • Constructors:
      • EXPR:TYPE, parentheses are not necessary when EXPR has operators with higher precedence.
      • ():TYPE, it calls the default constructor
      • (args...):TYPE
    • Regular Function Calls:
      • FUNCTION(), it calls a function without arguments
      • FUNCTION(args...)
      • obj.FUNCTION()
      • obj.FUNCTION(args...)
  3. They can be chained together, whereas it's not possible with UDLs in Cpp1.
    • Only one UDL can be applied to a literal in Cpp1.
  4. Constructors already can be templated, but UDLs cannot be templated.
    • UDL templates are not supported in Cpp1.
  5. It removes built-in literal prefixes and suffixes. They are inconsistent and redundant.
    1. They are visually inconsistent.
      • Some of them are prefix.
      • Some of them are suffix.
    2. Their behaviours are inconsistent when the constant of literal exceeds the type as described in this comment.
  6. The name to construct a literal and to declare a variable will be consistently the same.
    • It's not needed to declare a new name for literal suffixes.
    • The name of types are like a suffix that will construct an object.
  7. They can be applied to literals with qualified name (if they are within namespaces) unlike UDLs which need using statement before they can be applied to literals.
    • That's why UDLs in Cpp1 have to be prefixed with _, thus they will be distinguished from UDLs which are declared in the Cpp1 standard library.
  8. Unlike TYPE(args) it doesn't work with UFCS intentionally. UFCS should not work on constructors as described in this comment. Compare:
    // `TYPE(args)` with UFCS on it.
    x: = 10.Type(10, 20);
    
    // `(args):TYPE`
    y: = (10, 10, 20):Type;

Describe alternatives you've considered.

These are alternative solutions:

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions