GithubHelp home page GithubHelp logo

microsoft / bosquelanguage Goto Github PK

View Code? Open in Web Editor NEW
5.3K 169.0 296.0 49.03 MB

The Bosque programming language is an experiment in regularized design for a machine assisted rapid and reliable software development lifecycle.

License: Other

TypeScript 49.08% JavaScript 0.23% C++ 42.29% SMT 0.50% C 7.48% Elm 0.42%

bosquelanguage's Introduction

Bosque Programming Language

This repository is archived and active development of the Bosque Language is moving to an external open-source repository under @BosqueLanguage (github repo is here)!

Licensed under the MIT License PR's Welcome Build Health

The Bosque Project

The Bosque Programming Language project is a ground up language & tooling co-design effort focused on is investigating the theoretical and the practical implications of:

  1. Explicitly designing a code intermediate representation language (bytecode) that enables deep automated code reasoning and the deployment of next-generation development tools, compilers, and runtime systems.
  2. Leveraging the power of the intermediate representation to provide a programming language that is both easily accessible to modern developers and that provides a rich set of useful language features for developing high reliability & high performance applications.
  3. Taking a cloud-development first perspective on programming to address emerging challenges as we move into a distributed cloud development model based around serverless and microservice architectures.

The Bosque Language is a novel hybrid of functional programming language semantics and an ergonomic block & assignment-based syntax. This allows developers to organize code into familiar/natural blocks and compositions while, simultaneously, benefiting from the correctness and simplicity of a functional programming model (see code examples below). The language also provides a range of ergonomic features for writing high reliability code, such as Typed Strings, unit typedecls for primitives, and first-class assertions/pre-post conditions/invariants.

The Bosque Testing Framework provides a built-in unit testing system, a powerful new SMT powered property-based testing system, and the ability to symbolically search for errors that can be triggered by user inputs in the entrypoints to the program (see the bosque command section below). These tests and checks can find compact debuggable inputs that trigger and error or failing test and, in many cases, can also prove that there will never be a case with a “small repro” that triggers the error!

The Bosque Runtime is a novel pathology free design that focuses on predictable latency, pauses, and 99th percentile behavior. This starts with a new garbage collector that is guaranteed to never need a stop-the-world collection, that only uses live-heap + a small constant in memory to run, and (will eventually) supports background external defragmentation! Beyond the GC behavior the runtime design excludes pathological regex behavior, dynamic execution bailout overload, and catastrophic amortized operation behaviors such as repeated rehashing (instead using slower but stable log time persistent structures).

The Bosque API Types provide a way to specify an application interface in a clean manner that is independent of the specifics of the Bosque type system. This enables the auto-generation of input validation and encoding logic. We currently support a universal JSON encoding but more efficient representations are possible. This design ensures that Bosque APIs can easily be integrated into polyglot systems (e.g. microservice architectures) or integrated into existing codebases (e.g. Node.js or C++).

The Bosque Package Manager (see the bosque command section) provides a centralized way to organize, test, and build an application – either as a standalone command or to integrate into other applications via JSON APIs. This manager is designed to take advantage of the checking capabilities of Bosque and will enable developers to (1) test against imported code using auto-generated mocks and (2) check that package updates do not (intentionally or maliciously) change the package behavior, introduce new data outputs, or expose sensitive data to unintended outputs!

Documentation

Small samples of code and unique Bosque tooling are below in the Code Snippets and Tooling sections. A rundown of notable and/or unique features in the Bosque language is provided on the Language Highlights page and complete documenation for the language and standard libraries are on the Language and Libraries doc pages respectively.

Detailed Documentation, Tutorials, and Technical Information:

Code Snippets

Add 2 numbers:

function add2(x: Nat, y: Nat): Nat {
    return x + y;
}

add2(2, 3)     //5
add2(x=2, y=3) //5
add2(y=2, 5)   //7

All positive check using rest parameters and lambda:

function allPositive(...args: List<Int>): Bool {
    return args.allOf(fn(x) => x >= 0i);
}

allPositive(1, 3, 4) //true

Tuples and Records:

function doit(tup: [Int, Bool], rec: {f: String, g: Int}): Int {
    return tup.0 + rec.g;
}

doit([1, false], {f="ok", g=3}) //4

Sign (with default argument):

function sign(x?: Int=0i): Int {
    var y: Int;

    if(x == 0i) {
        y = 0i;
    }
    else {
        y = (x > 0i) ? 1i : -1i;
    }

    return y;
}

sign(5i)    //1
sign(-5i)   //-1
sign()     //0

Nominal Types Data Invariants:

concept WithName {
    invariant $name !== "";

    field name: String;
}

concept Greeting {
    abstract method sayHello(): String;

    virtual method sayGoodbye(): String {
        return "goodbye";
    }
}

entity GenericGreeting provides Greeting {
    const instance: GenericGreeting = GenericGreeting{};

    override method sayHello(): String {
        return "hello world";
    }
}

entity NamedGreeting provides WithName, Greeting {
    override method sayHello(): String {
        return String::concat("hello ", this.name);
    }
}

GenericGreeting{}.sayHello()          //"hello world"
GenericGreeting::instance.sayHello()  //"hello world"

NamedGreeting{}.sayHello()           //type error no value provided for "name" field
NamedGreeting{name=""}.sayHello()    //invariant error
NamedGreeting{"bob"}.sayHello()      //"hello bob"

(Algebraic Data Types)++ and Union Types

datatype BoolOp provides APIType using {
    line: Nat
} of
LConst { val: Bool }
| NotOp { arg: BoolOp }
| AndOp { larg: BoolOp, rarg: BoolOp }
| OrOp { larg: BoolOp, rarg: BoolOp }
& {
    recursive method evaluate(): Bool {
        match(this) {
            LConst                  => return this.val;
            | NotOp                 => return !this.arg.evaluate[recursive]();
            | AndOp{_, larg, rarg} => return larg.evaluate[recursive]() && rarg.evaluate[recursive]();
            | OrOp{_, larg, rarg}  => return larg.evaluate[recursive]() || rarg.evaluate[recursive]();
        }
    } 
}

AndOp{2, LConst{1, true}, LConst{1, false}}.evaluate[recursive]() //false
OrOp{2, LConst{1, true}, LConst{1, false}}.evaluate[recursive]()  //true

function printType(x: Bool | Int | String | None ): String {
    return match(x) {|
        Bool     => "b"
        | Int    => "i"
        | String => "s"
        | _        => "n"
    |};
}

printType(1.0f) //type error
printType(true) //"b"
printType(none) //"n"

Validated and Typed Strings:

typedecl ZipcodeUS = /[0-9]{5}(-[0-9]{4})?/;
typedecl CSSpt = /[0-9]+pt/;

function is3pt(s1: StringOf<CSSpt>): Bool {
    return s1.value() === "3pt";
}

ZipcodeUS::accepts("98052-0000") //true
ZipcodeUS::accepts("1234")       //false

is3pt("12")              //type error not a StringOf<CSSpt>
is3pt('98052'_ZipcodeUS) //type error not a StringOf<CSSpt>

is3pt('3pt'_CSSpt) //true
is3pt('4pt'_CSSpt) //false
entity StatusCode provides Parsable {
    field code: Int;
    field name: String;

    function parse(name: String): Result<StatusCode, String> {
        return switch(name) {|
            "IO"        => ok(StatusCode{1, name})
            | "Network" => ok(StatusCode{2, name})
            | _         => err("Unknown code")
        |};
    }

    function accepts(name: String): Bool {
        return name === "IO" || name === "Network";
    }
}

function isIOCode(s: DataString<StatusCode>): Bool {
    return s === 'IO'_StatusCode;
}

isIOCode("IO");               //type error not a DataString<StatusCode>
isIOCode('Input'_StatusCode)  //type error not a valid StatusCode string
StatusCode::parse("Input") //runtime error not a valid StatusCode string

isIOCode('Network'_StatusCode)               //false
isIOCode('IO'_StatusCode)                    //true

let ec: StatusCode = StatusCode{'IO'};
assert(ec.code == 1i); //true

Numeric Types

typedecl Fahrenheit = Int;
typedecl Celsius = Int;

typedecl Percentage = Nat & {
    invariant $value <= 100n;
}

32_Fahrenheit + 0_Celsius //type error different numeric types
101_Percentage            //invariant error

function isFreezing(temp: Celsius): Bool {
    return temp <= 0_Celsius;
}

isFreezing(5)          //type error not a celsius number
isFreezing(5_Celsius)  //false
isFreezing(-5_Celsius) //true

The bosque Command

The bosque command is the primary tool for building, testing, and managing bosque packages and applications. The bosque command can be run on sets of files or, preferably, used in conjunction with Bosque packages which are defined with a package.json format.

Calculator Example

To illustrate how packages and the bosque command work we have a simple calculator app in the impl/src/test/apps/readme_calc/ directory (along with more interesting tic-tac-toe and rental apps).

This directory contains a package.json file which defines the package. As expected it has required name/version/description/license fields. The next part of the package definition, the src entry, is a list of source files (or globs) that make up the core logic of the application. Finally, we define two sets of files (or globs) that define the entrypoints of the application that will be exposed to consumers and a set of testfiles that can be used for unit-testing and property-based symbolic checking.

Calculator Source Code, Entrypoints, and Test Definitions

The source code file, calc_impl.bsq, for the calculator has two simple function implementation (sign and abs):

namespace Main;

function abs_impl(arg: BigInt): BigInt {
    var res = arg;

    if(arg < 0I) {
        res = -arg;
    }
   
    return res;
}

function sign_impl(arg: BigInt): BigInt {
    return arg > 0I ? 1I : -1I;
}

These functions are used, along with some direct implementations, to create the external API surface of the package (defined in the entrypoints files with a .bsqapi extension). The calculator exports several functions including div which uses a Result to handle the case of division by zero and uses the pre/post features of the Bosque language (ensures) to document the behavior of the abs and sign methods for the clients of this package.

namespace Main;

//More entrypoint functions ...

entrypoint function div(arg1: BigInt, arg2: BigInt): Result<BigInt> {
    if(arg2 == 0I) {
        return err();
    }
    else {
        return ok(arg1 / arg2);
    }
}

entrypoint function abs(arg: BigInt): BigInt 
    ensures $return == arg || $return == -arg;
    ensures $return >= 0I;
{
    return abs_impl(arg);
}

entrypoint function sign(arg: BigInt): BigInt 
    ensures $return == 1I || $return == -1I;
{
    return sign_impl(arg);
}

The run Action

The run action in the bosque command provides a simple interface for invoking the entrypoints from a command line using JSON values. The syntax run [package.json] [--entrypoint Namespace::function] will load the code/api specified in the package (default ./package.json) and find/run the specified function (default Main::main). The arguments can be provided on the command line, --args [...], or via stdin. The image blow shows how to execute the div and sign APIs.

The test Action

The test action handles running unit-tests and property-tests defined in the testfiles (with a .bsqtest extension). All functions that are declared as chktest functions will be run. Functions with 0 arguments are physically executed while functions with arguments are treated as parametric property tests and checked with the SMT solver for small inputs that may violate the desired property (i.e. the test returns false).

namespace Main;

chktest function abs_neg(): Bool {
    return abs_impl(-3I) == 3I;
}

chktest function sign_pos(): Bool {
    return sign_impl(5I) > 0I;
}

chktest function sign_neg(): Bool {
    return sign_impl(-4I) < 0I;
}

chktest function sign_neg_is_minus1(x: BigInt): Bool 
    requires x < 0I;
{
    return sign_impl(x) == -1I;
}

chktest function sign_pos_is_1(x: BigInt): Bool 
    requires x >= 0I;
{
    return sign_impl(x) == 1I;
}

Running the test action as shown results in 3 tests being identified as unit-tests and physically executed with 2 tests being identified as parametric property tests and checked symbolically. In this app all 3 of the unit-tests pass and the symbolic checker is able to prove that one of the property tests is satisfied for all (small) inputs. However, the other property test does have a violating input, namely when x is 0 when the function sign_impl evaluates to -1 but the expected property is that the sign should be 1.

The apptest Action

The apptest action takes the power of the symbolic checker that Bosque provides and applies it to possible runtime errors, assertion failures, pre/post conditions, and invariants that may be triggered by a client calling an API provided in the package entrypoints. Running the apptest command takes each entrypoint function and checks all possible errors reachable to either (1) find a small repro input that triggers the error or (2) prove that no such small input exists.

This results in 2 checks of postconditions, for sign and abs, and one check for a possible div-by-zero in the div entrypoint. In all three cases the checker is able to prove that there is no input that can trigger any of these errors or violate any of the post-conditions!

The other apps have more interesting code, tests, and errors to experiment with as well.

Installing the Bosque Language (Development)

In order to install/build the project the following are needed:

  • 64 bit Operating System
  • The LTS version of node.js ( According to your OS )
  • Typescript (install with: npm i typescript -g)
  • Git and git-lfs setup
  • A C++ compiler -- by default clang on Linux/Mac and cl.exe on Windows

Note: If you are running examples from the "Learn Bosque Programming" book please use the LearnBosqueProgramming branch which is sync'd with the version of code used in the book.

Build & Test

The impl directory contains the reference implementation parser, type checker, interpreter, and command line runner. In this directory, build and test the Bosque reference implementation with:

npm install && npm test

The Z3 theorem prover is provided as a binary dependency in the repo via git LFS. To ensure these are present you will need to have git-lfs installed, run git lfs install to setup the needed hooks, and pull.

Visual Studio Code Integration

This repository provides basic Visual Studio Code IDE support for the Bosque language (currently limited to syntax and brace highlighting). The installation requires manually copying the full bosque-language-tools/ folder into your user .vscode/extensions/ directory and restarting VSCode.

Contribute

This project welcomes community contributions.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Please refer to Contribution Guidelines for more details.

License

Code licensed under the MIT License.

bosquelanguage's People

Contributors

0xflotus avatar abhinavsagar avatar arkark avatar brakmic avatar brianwhited avatar catchmareck avatar clegoz avatar datschy avatar dhayalramk avatar emmet-m avatar enhsaihan-d avatar hearot avatar hong4rc avatar jimmyhmiller avatar joelibaceta avatar lonelyenvoy avatar mairwunnx avatar microsoft-github-policy-service[bot] avatar microsoftopensource avatar mrkmarron avatar msftgits avatar narendra-kamath avatar plankp avatar rtoal avatar stephen-oneil avatar terryag avatar thammarith avatar tumevoiz avatar viir avatar wizofe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bosquelanguage's Issues

Implement Const/Copy cleanup after MIR lowering

Currently the translation from the AST representation to the compiler MIR representation is pretty direct and leaves redundant constant and copy assignments. This is inefficient and makes it harder to understand the MIR code.

A simple block level copy/const propagation pass would help this out a lot.

Thunk blocks

These are handy. We would like to implement them.

TypeError: Cannot read property 'invoke' of undefined

I was trying to code my own max function in Bosque when I got this: TypeError: Cannot read property 'invoke' of undefined.

I'm using Windows 10 and I used node bin\test\app_runner.js over.bsq to launch the script.

Output
Reading app code...
Executing app code...
fail with exception -- TypeError: Cannot read property 'invoke' of undefined
Code - over.bsq
namespace NSMain;

function max(x: Int, y: Int): Int
    ensures _return_ == x || _return_ == y;
{
    if (x >= y) {
        return x; 
    } else {
        return y;
    }
}

function main(): Int {
    var x = 10;
    var y = 20;

    return max(x, y);
}

Predicate transformers/symbolic execution

This is a priority for this project. In theory, and our hand worked examples, the Bosque language allows the effective manipulation of symbolic state for the code. This is foundational to many of the other things we want to do for tooling and would be an exciting step in PL research.

We will be working on parts of this but are happy to collaborate with others who may be interested in the topic.

Implement statement expressions

We want to provide the ability to use if and match as expressions as well as statements (also want to allow block expressions).

Tilde symbol

The language itself sounds very interesting, however I would like to mention that tilde symbol ~ in my opinion isn't a very good choice. I know that there are plenty of programming languages that use this symbol, but it's not very easy to type on, for example, Polish, Swedish, Finnish and Danish keyboards. It's not in natural position, in some cases it has to be followed by other key to appear and it is also used to make special characters. For instance ~+a in Polish gives ą. I'm pretty sure it isn't even shown on some Italian keyboards.

Optional record properties are not sound under the subtyping relationship

And allow exactly the kind of ambiguity and accidental complexity you seem to want to avoid. TypeScript itself has this problem and is part of why is has separate subtype (which optional-ness doesn't participate in) and assignable relationships.

Specifically, since {x: Int, y?: Int} <: {x: Int} <: {x: Int, y?: String} (also the other way around - this also destroys the desirable partial ordering you'd like the subtype relationship to have), aliasing can cause the type of a field to be "forgotten" and then replaced with a different, incompatible type; creating potential unexpected behavior on the read of such a property.

You probably want to fix this as early as possible, so you're not stuck with an unsound relation ;)

Question: Threading / Async

What is the thinking around threading model? Will it adopt a async / await model, coroutines or something else?

Question: Why bsl when there is already TypeScript

May I ask some questions?

According to the test script filed in the "tictactoe" example program, bsl is compiled to JavaScript as its target language. Why do we need another "compiled-to-JS" language when there is already TypeScript?

Is it the final goal of this language that bsl is always compiled to js? If the answer is "yes", why don't we improve those features on TS?
Is there a plan that we make a runtime for bsl, or that bsl is compiled to binary code in the future?

SSA form for MIR

Many tasks we want to do will be much simpler on a SSA form IR. Add a phase to SSA convert the MIR representation after translation (and copy/prop in issue #16).

Variable threading

Often we need to thread an "environment" through code:

var env = ...;
@[var res1, env] = foo(env);
@[var res2, env] = bar(env, res1);
...

This is clumsy and verbose. We would like to thread env as a updateable ref parameter instead:

var env = ...;
var res1 = foo(ref env);
var res2 = bar(ref env, res1);
...

Where foo and bar can use/modify the env parameter.

Value and reference types

In Bosque there is no way to tell object reference identity so converting from by-ref to by-value is purely a performance issue (no impact on behavior).

I would like to have type annotation that specify by-value storage for a type. This also involves coercion operators and, potentially, the introduction of C# style reference types.

Field "degrees" is required and must be assigned a value in constructor

While I was trying to use Bosque, I ran into a problem and got this: Field "degrees" is required and must be assigned a value in constructor. The problem is: I'm already passing the degrees parameter!

I'm using Windows 10 and I used node bin\test\app_runner.js angles.bsq to launch the script.

Output
Reading app code...
Parse error -- ["angles.bsq",19,"Field \"degrees\" is required and must be assigned a value in constructor"]
Code - angles.bsq
namespace NSMain;

entity Angle {
    field degrees: Int;
    field primes: Int = 0;
    field seconds: Int = 0;

    method normalized(over360?: Bool): Angle
        ensures _return_.primes < 60;
        ensures _return_.seconds < 60;
    {
        var! seconds = this.seconds % 60;
        var! primes = (this.primes + (this.seconds / 60)) % 60;
        var! degrees = this.degrees + (this.primes + (this.seconds / 60)) / 60;
        
        if (over360 && degrees > 360) {
            degrees = 360;
        }

        return Angle@{degrees, primes, seconds};
    }
}

entrypoint function main(): Angle {
    var angle = Angle@{degrees=0, primes=60, seconds=60};

    return angle->normalized(); // Output should be: Angle@{1, 1, 0}
}

General MIR tools

We have a JSON like dump of the MIR code. It would be nice to have some tooling to easily display, load, etc. this representation for debugging and development work.

Formalize Semantic Versioning

What does it mean to bump the patch/minor/major level of a semantic version for our packages? Can we formally specify this hopefully validating later?

Affine/Unique/Owner type annotations

Values are immutable in the Bosque language but this can lead to heavy copy and data movement. A interesting research question is the design of an affine/unique type language that allows us to perform mutable operations on values -- particularly with bulk operations.

At the same time having some unique/borrowed/scoped typing support would also be useful for performing stack or pool allocation.

Why is Bosque moving away from regular generic syntax

Regarding the following example:

function allOdd(...args: List[Int]): Bool {
    return args.all(fn(x) => x % 2 == 1);
}

Both TypeScript and C# use <> to define and consume generics while Bosque uses [].

Is there any reason for it? Because all languages supported by Microsoft should have the same "syntax standards".

I mean, there are some differences between TypeScript and C# but the standards are still there:

  • Generics <>
  • Arrays []
  • Object initialization {} (e.g Anonymous functions for C#)
  • Etc...

Is there any constraint that requires Bosque to move away from the microsoft's "standards"?

Also [] seems confusing.

function allOdd(...args: List<Int>): Bool {
    return args.all(fn(x) => x % 2 == 1);
}

Question Compiler

Question: Exists there a plan to create a compiler for .net core?

GC design

The fact that Bosque does not have reference identity opens up some interesting GC opportunities.

For example one could potentially do something like racy parallel copies for collection which may result in some pointers to the old version and some to the new copy. This would be ok as it does not impact the semantics of the program and, if it is infrequent, should not impact perf/fragementation much until it is repaired next collection.

I am personally very intersted in the possbility of implementing an RC based system (potentially with unique type support - issue #28) to favor performance predictability over max throughput.

Question: Visibility

I've seen the hidden keyword on some method examples.

  1. what is the scope of this visibility? Class? Namespace?
  2. how would a hidden field work with the way constructors work?

Type checking in JS

JavaScript is almost always used to deal with dynamic input sources, like payloads from APIs. One of the biggest drawbacks to TypeScript is its purely static type system with no way to automatically convert any to the expected stronger type (TypeScript default settings will even not alert you to the unsafe cast), without manually implementing type guards.

I can't find any information on whether Bosque is dynamically or statically typed, but it would be awesome if Bosque could detect type casts and emit a type validation function for that operation. It would gain a huge advantage over TypeScript.

Question: How to submit CLA

Hello,

I have the CLA downloaded, filled out and signed, but cannot find where to send it on cla.microsoft.com.

Where should I submit this to allow me to contribute to this project?

Thanks,

Ryan

Implement synthesis blocks

Inspired by this paper I would like to implement synthesis blocks as a first class language feature (and a synthesis engine to support it).

Several questions are what can a programmer specify for the block, types, pre/post, examples, etc. and what is the synthesis methodology.

Language Syntax Discussion

There seem to be a number of comments thoughts on language syntax. This issue will consildate general thoughts and suggestions. Other more specific issues can be created and referenced from here.

Unclear list processing examples

I'm not quite sure what's going on in the examples of operations on lists:

var v: List[Int?] = List@{1, 2, none, 4};
  
//Chained - List@{1, 4, 16}
v.filter(fn(x) => x != none).map[Int](fn(x) => x*x)

//Piped none filter - List@{1, 4, none, 16}
v |> filter(fn(x) => x != none) |> map[Int](fn(x) => x*x)

//Piped with noneable filter - List@{1, 4, 16}
v |??> map[Int](fn(x) => x*x)

//Piped with none to result - List@{1, 4, none, 16}
v |?> map[Int](fn(x) => x*x)

First of all I have not been able to run any of those. I looked at the other code examples and realized that -> seems to be the actual method call operator but that still did not help me. Execution fails with the error fail with exception -- TypeError: Cannot read property 'invoke' of undefined which I imagine comes from somewhere in the interpreter internals. Is this not implemented yet?

Another thing is that I'm pretty sure that the second example should return List@{1, 4, 16} since it manually filters out none values.

Improve VSCode syntax highlighting

The current grammar for syntax highlighting in VSCode is pretty basic. It would be nice to enhance it a bit to be richer and more informative.

Pattern match and Structured assignment check & bind

Structured assignment and the match statement conditions need to check if a given structure value is compatible with a template e.g.:

var @{x, @[1, y]} = @{"ok", @[5, 6]}

If the template is not compatible the structured assign will fail (and match will continue searching) so we want to implement the check operation and bind operation seperately.

Subtyping

Why is this:

{f: Int, g?: Bool} <: {f: Int} // false, why?
[Int] <: [Int, ?:Bool]  // true, why?

By (Structural Type System), it would seem to me that these (and similar ones) should be reversed.

Is there more info on Bosque's type system somewhere?

tsc -p tsconfig.json in package.json throws error

When running the command npm run-script build, the error, below, is thrown. There seems to be an issue with the tsc -p tsconfig.json line in package.json.

0 info it worked if it ends with ok
1 verbose cli [ 'C:\\Program Files\\nodejs\\node.exe',
1 verbose cli   'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli   'run-script',
1 verbose cli   'build' ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'prebuild', 'build', 'postbuild' ]
5 info lifecycle [email protected]~prebuild: [email protected]
6 info lifecycle [email protected]~build: [email protected]
7 verbose lifecycle [email protected]~build: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]~build: PATH: <lots of local paths>
9 verbose lifecycle [email protected]~build: CWD: <custom_directory>\BosqueLanguage\ref_impl
10 silly lifecycle [email protected]~build: Args: [ '/d /s /c', 'tsc -p tsconfig.json' ]
11 silly lifecycle [email protected]~build: Returned: code: 1  signal: null
12 info lifecycle [email protected]~build: Failed to exec build script
13 verbose stack Error: [email protected] build: `tsc -p tsconfig.json`
13 verbose stack Exit status 1
13 verbose stack     at EventEmitter.<anonymous> (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\index.js:301:16)
13 verbose stack     at EventEmitter.emit (events.js:189:13)
13 verbose stack     at ChildProcess.<anonymous> (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14)
13 verbose stack     at ChildProcess.emit (events.js:189:13)
13 verbose stack     at maybeClose (internal/child_process.js:970:16)
13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
14 verbose pkgid [email protected]
15 verbose cwd <custom_directory>\BosqueLanguage\ref_impl
16 verbose Windows_NT 10.0.16299
17 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "run-script" "build"
18 verbose node v10.15.3
19 verbose npm  v6.4.1
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] build: `tsc -p tsconfig.json`
22 error Exit status 1
23 error Failed at the [email protected] build script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]

running tsc -p tsconfig.json on it's own yields the error:

error TS5023: Unknown option 'p' Use the '--help' flag to see options. error TS5007: Cannot resolve referenced file: 'tsconfig.json'.

I newly installed the latest x64bit LTS version of Node.js (its been awhile since I last used it).
node -v yields v10.15.3
npm -v yields 6.4.1
tsc -v yields 1.0.1.0

Is this an issue with the package.json? The current LTS version of Node.js does not seem to have '-p' as an option. The mann page for tsc does not show a '-p' option

WASM compilation

Currently we have a simple (and poor performance) interpreter reference implementation. Having a WASM compiler target and runtime. This will also require some GC design (see issue #30) but it might be ok to start with a simple RC based design.

Implement lightweight reference analysis

It would be great to have a lightweight reference analysis to support optimization and basic analysis tasks.

A DSA style analysis may be very intersting here as it is fully context-sensitive, and in SSA form the flow will be equivalent to fully flow sensitive as well, while being very fast. We probably want to modify the info included in the analysis a bit but this should be pretty straight forward.

Variable name '_result_' is not defined

I tried to use the ensures - "post-condition" feature because I think it's one of the best features Bosque has got, but I got an error: Variable name '_result_' is not defined.

I used node bin/test/app_runner.js angles.bsq to run the code. I'm using Windows 10.

Code - angles.bsq
namespace NSMain;

entity Angle {
    field degrees: Int = 0;
    field primes: Int = 0;
    field seconds: Int = 0;

    method normalized(over360?: Bool): Angle 
        ensures _result_.primes < 60;
        ensures _result_.seconds < 60;
    {
        var! seconds = this.seconds % 60;
        var! primes = this.primes + (this.seconds / 60) % 60;
        var! degrees = this.degrees + (this.primes + (this.seconds / 60)) / 60;
        
        if (over360 && degrees > 360) {
            degrees = 360;
        }

        return Angle@{degrees, primes, seconds};
    }
}

entrypoint function main(): Angle {
    var angle = Angle@{0, 60, 60};

    return angle->normalized();
}

Memoize (and singleton) pragmas

Memoization and/or singletons with lazy initializtion are very useful patterns and important performance optimizations. In Bosque they are also semantics preserving since there is no reference identity. However, implementing them in a functaional language can be hard.

So, we want to implement "optmization pragmas" for functions/methods for singleton and memoize optmizations.

#pragma memoize(cache=256, replace="LRU")
function square(x: Int): Int {
...
}

As shown in the example we want to allow control over the size and replacement policies. We can also check that the arguments are valid for comparison at compile time.

Error in README.md

Probably you have error in README.md in Update y-value on point Record example:

updateY(@{x=1, y=2, z=3}, 5) //@{x=-1, y=5, z=3}

If updateY update y-value why x-value changed from 1 to -1?

Probable typo in whitepaper

Not sure if this is the best place to put this, but I believe I found a minor typo on page 3 of the Bosque whitepaper and thought the author might appreciate it if I reported it somewhere.

Relevant sample code:
"""
/ / c a l l s with e x p l i c i t arguments
var x = nsum ( 0 , 1 , 2 , 3) ;
[...]
/ / c a l l s with spread arguments
var l = @[0 , 1 , 2 , 3 ] ;
var y = nsum ( 0 , . . . l ) ; / / same as x
"""

Followed by the remark I believe is erroneous:
"""
Semantically, the call nsum(0, ...l) is the same as nsum(0, l[0], l[1], l[2])
"""

Suggested correction:
Given that l has 4 elements, I would expect that nsum(0, ...l) is equivalent to nsum(0, l[0], l[1], l[2], l[3]), not nsum(0, l[0], l[1], l[2]), which would be nsum(0, 0, 1, 2) and therefore not equal to x.

Additional note in case this reaches the author:
I would caution against the use of the letter l as a variable name given that it is effectively indistinguishable from the number 1 in all of the typefaces I have seen thus far in the paper. Since both are used as arguments in the example I reference above, changing the variable name to something other than l would improve clarity!

I hope this helps!

Some Questions to the overview document

Bosque looks like a very promising modern language.

After reading the docs there are some points unclear to me.
Could you help me understand them?

I have sorted them after the sections in the overview document.

0.4

Why only typed strings, why no typed float/integers?
Then you could allow the compiler to check some arithemtic calculations

var a = 3m +2m;  // ok
var b = 3m + 2s; // error

Are they inspired by TypeScript?

0.6

Are there some typos?

Do you mean var! instead of var?

Why is the result of

var l = @[7, 8, 9];
// ...
l<+(@[5, 6]); //@[7, 8, 5, 6]

@[7, 8, 5, 6] and not @[7, 8, 9, 5, 6] ?

Typo here:

var r = @{f=7, g=8};
r@{f, h};         //@{f=1, h=none}

Should f be here 7?

What is the difference between

r<~(f=5, h=1);    //@{f=5, g=8, h=1}

and

r<+(@{f=5, h=1}); //@{f=5, g=8, h=1}

?

What is the difference of the merge and update operator for records?
For tuples the merge operator is an èxtend operator?

0.8

  • .map does the same as |> map ?
    Why two operators . and |> doing the same?
    You state that . is always eager and only |> can be lazy.
    But this is not true, see Apache Spark or Rust Iterator Trait.
  • What about introducing chainging or kleisli operators here?
    Like var y = (f | g | h)(x) which is the same as var y = f(g(h(x)));
  • Does the |?> has a special purpose only for map?

5.7

What is the purpose of (Baz + Bar)::m(0) ?
Why not simply Baz::m(0) or Bar::m(0) ?

Others

Does the language also support floating point numbers?

Consider adding reference cells or similar explicitly mutable types

Apologies if there's something like this already on the spec, but I didn't see it if so. Coming from the SML world, ref cells allow you to explicitly break the immutability rule.

This is costly for all the obvious reasons, but it allows for datatypes like the SML/NJ Queue.

Module/Package structure and implementation

We have namespaces implemented but do not yet provide a way to package a block of code for sharing or use accross projects. There needs to be some thought and implementation on what this looks like - how are version conflicts resolved, what is exported, what meta-data is useful etc.

Your example shows me error

Hey,
I tried your example of adding two numbers but it shows me this error message:
(function (exports, require, module, __filename, __dirname) { function add2(x: Int, y: Int): Int {
^

SyntaxError: Unexpected token :
at new Script (vm.js:79:7)
at createScript (vm.js:251:10)
at Object.runInThisContext (vm.js:303:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
at startup (internal/bootstrap/node.js:283:19)

I wrote it via vscode extension. Is it problem with my configuration or something?

Quick return

When implementing something like a parser where every call can produce an Result | None there is a lot of if conditional flows. Does it make sense to add some shorthand for this like:

var res = foo(x, y) with return on _result_ == "bad" with "not cool";

We can probably do some sane defaults where the condition is a none check and the result expression is the computed result.

Default values for function arguments

At the moment, Bosque only supports optional arguments, which are in fact implemented as arguments with the default value of none. There is no way to set any other default value.

Given the functions

function fun1(a: Int? = none; b?: Int, ...c: List[Int])
function fun2(a: Int = 42, b: Int, c?: Int, ...d: List[Int] = @[47, 11])

The following code

fun1(1)
fun1(1,2)
fun2(1)
fun2(1,2,3)
fun2(a=1,2,3)

should be equivalent to

fun1(a=none, b=1, c=none)
fun1(a=none, b=1, c=@[2])
fun2(a=42, b=1, c=none, d=@[47, 11])
fun2(a=42, b=1, c=2, d=@[3])
fun2(a=1, b=2, c=3, d=@[47, 11])

The rest operator should always absorb superfluous arguments, when all other arguments have an assigned value.

language syntax is not totally incomprehensible

Clearly, great progress has been made towards inscrutability, but there are still areas where increased semantic obtuseness can be attained. The use of even a few standard operators ... from the C/C++/C# canon ... like the assignment operator, can be made much more difficult to use.

How about: <= makevar ::string:: => some string

The use of Greek letters from APL could also be considered.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.