Skip to content

Design directions

Shachar Shemesh edited this page Jul 9, 2018 · 3 revisions

Please remember that many things are still in flux. If the naming styles are not consistent, this is not intentional, and will be fixed as things progress.

There are two purposes for this page. The first is to flash out problems with the language before implementation begins. The second is to let new-comers get a taste of how programming in Practical will look like.

This page is written before any work has started on coding, implementing or writing code using the language. It will be very interesting to see how many of those objectives would be reachable.

Items marked with (?) are items I'm not sure about.

Compatibility to C

  • The syntax will be C like. Curly braces, semicolons, and white-space indifference.
  • Fix operator precedence bugs that invite errors in C. Same for confusing evaluation rules of C (like integer promotion of operations). Compiler warning if an expression would evaluate in its entirety differently between C and practical.

Example:

short func1(short a, short b) {
  return a+b; // No warning. C and practical would always return the same result
}

int func2(short a, short b) {
  return a+b; // Warning: C would promote to int, treating overflows differently than practical
}
  • No implicit narrowing conversions.
  • Rethink some C and C++ UBs.
    • Evaluation order in function calls
    • integer overflows(?)

Practical features

Default const

The default mode for new variables is const. Use the mutable keyword to indicate that a variable is, well, variable.

Default unsigned (?)

The default mode is unsigned.

Allow introducing explicit UBs

Exact mechanism TBD. For the time being, this will be phrased as an assert.

void func(int a, int b) {
  assert(a>5);
  // It is undefined what happens if a==4 at this point, even in release build
}

This can affect the C compatibility rule above:

int func(unsigned short a, unsigned short b) {
  assert(a<10);
  assert(b<20);
  return a+b; // No warning, as no short overflow could happen
}

Function attributes

I'm using the D notation here. Final syntax TBD.

Built-in attributes have the same syntax as compiler-defined ones.

Compile time execution

Every code written can be either run-time, compile-time or both compatible. If the code is compile-time only, it will not be generated at the run time at all.

Certain capabilities are compile time only or run time only.

Using a run-time only capability from a compile-time only context is a compilation error and vice versa. This is true whether the context is such by explicit attribute or by inference.

int func1(int value) @compiletime;

// Run time only by explicit attribute
int func2(int value) @runtime;

// Both run and compile time
int func3(int value);

// Run time only: uses a pointer
int func4(int* value);

// Compile time only: accepts a type
int func5(type T);

Compile time only first class citizens

In compile time context, there are some first-class citizens that are not available at run time

The Type type

A variable of type type can be any (and only) type.

C++ decltype primitive can, therefor, be implemented as a library function (using the C++ syntax for templates):

template <class T> Type decltype(const T &arg) {
   return T;
}

We do not need to annotate decltype with @compiletime, as only a compile time function can return type.

Also note that we only need the templating in order to derive the type. A function returning (or accepting) type need not be templated at all.

Here is an example of arrayify:

Type arrayify(Type baseType) {
  return baseType[];
}

This is not a template function! It is a function manipulating types.

ArgumentsList

There are two kinds of argument lists.

The first is an argument list as used by function declarations:

struct FunctionParameter {
  Type type;
  String name;
}

typedef FunctionParameter[] FunctionParameters;

The second is an arguments list as passed to function:

struct FunctionArgument : FunctionParameter {
  unique_ptr<type> value;
}

typedef FunctionArgument[] FunctionArguments;

The pseudo definitions above non-withstanding, the really interesting thing about FunctionParameters and FunctionArguments is that you can:

  1. Return them from a function
  2. Use them to call a function

This means you can use (compile time) functions to calculate the arguments you want to pass to a function, and then use that:

void someFunction( int arg1, string arg2 );
FunctionArguments calcSomeFunctionArguments( int seed );

someFunction( calcSomeFunctionArguments(5) );

Clone this wiki locally