Stabel

View Ticket
Login
2021-09-25
12:37 Closed ticket [c2996a5e70]: 0.3.0: Syntax changes plus 3 other changes artifact: c825f20696 user: robin.hansen
12:36
Error handling for fully qualified refs. This concludes the syntax changes language proposal. [c2996... Leaf check-in: 106eea3696 user: robin.hansen tags: trunk
2021-09-24
09:35
Integers can now be represented directly in multifunction pattern matching. [c2996a5e70] check-in: 71f2929943 user: robin.hansen tags: trunk
2021-09-20
16:33
Aliases can now be implicit [c2996a5e70] check-in: 7c8e530718 user: robin.hansen tags: trunk
16:18
Change order of fields for alias: metadata [c2996a5e70]. check-in: 24cb64e9da user: robin.hansen tags: trunk
2021-09-18
10:28
Change auto-generated ctor name for memberless structs. [c2996a5e70] check-in: 2badc579e3 user: robin.hansen tags: trunk
2021-08-09
11:38 New ticket [c2996a5e70] 0.3.0: Syntax changes. artifact: a259e0aba9 user: robin.hansen

Ticket UUID: c2996a5e707325c18737ef58e3928b95be8b97b5
Title: 0.3.0: Syntax changes
Status: Closed Type: Language_Proposal
Severity: Cosmetic System: Compiler
Resolution: Fixed Modified: 2021-09-25 12:37:01
User Comments:
robin.hansen added on 2021-08-09 11:38:54:

The following document outlines the language proposal process: Language Proposals.

Syntax changes

After some experience with the 0.2.0 release, it has become clear that certain syntax doesn't work as well as hoped. This proposal suggest a few changes be made to the current Stabel syntax.

Add package level reference

You can currently refer to types and functions in other modules in two ways:

  • Prefix the wanted type or function with the module path without a leading forward slash. This is known as an internal module reference, and will only resolve to modules that exist within the same package as the reference. An example of such a reference is: internal/module/function.
  • Prefix the wanted type or function with the module path with a leading forward slash. This is known as an external module reference, and will only resolve modules that exist outside of the same package as the reference. An example of such a reference is: /external/module/function.

Having these kind of references makes it easier for the reader to understand where a function resides. It also makes avoids a collision in case there exists an internal and an external module of the same name.

However, if there exists multiple external modules of the same name, there's no way to specify which module the user wishes to reference.

I'd therefore like to propose a new type of reference, called a package module reference, which is a reference that begins with a double forward slash. This reference is required to start with the package name before the module path. An example of such a reference is: //package/name/module/function.

There are alternatives to this solution, and I'd love to hear people's opinions on all of them:

  • Only have two types of references. Internal module references work as before, but the external module reference should be replaced with the package level reference but using the external module syntax. This way there will never be any ambiguity on what module is being referenced, and the programmer can always use imports and aliases to make the reference easier to type.
  • Instead of using double forward slash to signify a package level reference, use an infix operator to separate the package name from the module path. Like: /package/name@module/path/function.

New constructor name for member-less structs

When defining a struct, the compiler will auto-generate constructor-, getter- and setter-functions for you.

In 0.1.0 the constructor would always start with a > character, to signify that the current values on the stack is consumed to return the type in question. This way, an expression like 1 2 >Point could be read as 1 and 2 goes into Point.

For the 0.2.0 release we changed this for member-less structs. Since member-less struct constructors doesn't consume anything from the stack in order to create the type, the naming scheme was confusing. In 0.2.0 the auto-generated constructor for member-less structs was simply the type name itself.

I now realise that this doesn't play all too well with the module system. If you wish to expose the MemberlessStruct type, and that type doesn't have any members, there's no way to do so without also exposing the constructor since they both share the same name.

For 0.3.0 I therefore propose to change the auto-generated name for member-less structs to end with a > character. This matches the naming convention for getter functions, and also reads well. Example: MemberlessStruct>.

Alternative:

  • Add a new keyword to modules called expose-types:. This lets you expose functions and types in separate statements, which would allow a constructor and type to share the same name and still have different expose values.

Implicit aliasing

The current syntax for aliasing a module looks like:

	defmodule:
	alias: mod /external/mod
	:

This will let you reference /external/mod/function as mod/function

I propose to change this to:

	defmodule:
	alias: /external/mod mod
	:

In addition I propose that the second argument, the alias itself, becomes optional. If not provided, it will simply be inferred to be the last part of the module path. In this case, mod. In nearly all the Elm code I write, this happens to be the case, so making this behaviour implicit would save me some typing.

Support integer literals directly in pattern matches

We currently support matching integer literals in multi-functions with this syntax:

	defmulti: is-one?
	type: Int -- Bool
	: Int( value 1 )
	  True
	else:
	  False

This is unintuitive. We treat Int as though it was a struct, when in reality it's more of a union. I therefore suggest changing the syntax to:

	defmulti: is-one?
	type: Int -- Bool
	: 1
	  True
	else:
	  False