Vous êtes sur la page 1sur 4

Tridash: Why yet another programming language?

Alexander Gutev

31 Aug 2019 CPOL

Another Programming Language?. CodeProjectI recently released version 0.4, the first version that is remotely usable, of Tridash, a
programming language I've been working on...

Another Programming Language?


CodeProject
I recently released version 0.4, the first version that is remotely usable, of Tridash, a programming language I've been working on.

You're probably wondering, with all the existing programming languages available supporting a variety of programming paradigms
ranging from low-level imperative programming to logic programming, why on earth would I create a new programming language.
What problem do I aim to solve with this new language that has not been solved already by the hundreds of programming
languages that came before it. To tell you the truth I mainly created it because I like writing software and trying out new ideas.
Creating a programming language was an interesting and fun exercise in itself. However this a legitimate reason for creating a new
language, besides the programming exercise.

I've tried many languages ranging from low-level C, object oriented languages such as C++, C#, and Java, scripting languages such
as Python, PHP and JavaScript and languages which implement entirely different programming paradigms such as Common Lisp,
Prolog and Haskell. Whilst all languages excel at different points, they are all rather lacking when it comes to creating robust and
interactive applications. Specifically they are lacking when it comes to managing the state of the application and the changes in its
state triggered by the user interaction or external events such as a data arriving on the network.

State Management Problem


Imperative programming languages allow for raw unrestricted mutable access to the underlying memory, that means you can read
and write to virtually any address in the process's memory space. These languages generally provide few tools for managing the
state of the application. It is entirely up to the programming to establish "listeners" for each interesting event, such as the user
entering text in a text field or the arrival of data on the network, and then manually update the state, by mutating memory directly,
of the entirely application. 

As a simple example, consider an application consisting of a text field, in which the user enters his/her name, after which a greeting
(with the user's name) is displayed.

We want something similar to the following:


In an imperative programming language you would have to setup a listener for the event which is fired when the user enters text in
the field, and then manually update the label below the field, by writing to the memory location in which the text is stored, either
directly or by some setText  method/function, and then calling a redraw method/function. The actual mechanics may differ,
depending on the language and GUI framework, however the point is that it is up to the programmer to update the state of the
components, which comprise the application, when the state of a component changes. Besides being both tedious and error-prone,
the resulting application is usually inflexible with the actual application logic intertwined with the event listener and state updating
boilerplate. As a result, changes in the application logic often require an infrastructural change in the code. The problem is
exasperated when concurrency is involved. Suddenly the application logic is buried in layers of thread synchronization logic.

Functional programming languages eschew state completely. In a pure functional programming language, memory does not exist.
Instead the entire application is structured as a pure function, i.e. without side effects, of its input, which produces the application's
output. In order to build interactive applications using a pure functional programming language, all application events (both user
and external) are grouped into an infinite list, referred to as a stream, and the application is structured as a pure function taking the
stream as input. The output is a new "application" object containing the updated GUI and any IO actions which are to be performed.
Whilst this approach offers a lot of benefits, such as being amenable to parallelisation due to the application being structured as a
pure function without side effects and thus without concurrent writes to the same memory location, it requires restructuring the
application logic as a function that takes an old application object as input and produces a new application object as output.
Effectively you have to think of an interactive application as though it is a non-interactive application, which simply takes an input,
produces an output and exits. Furthermore you still have to manually compute a new component from the old component for each
component comprising your application. It is also up to you to keep track of which components are affected by the event. The
addition of new application components, which are affected by some events, requires a change to the application "main" function.

Neither pure functional programming nor imperative programming allow you to declaratively specify the application state as a set
of components which are dependent on the state of other components. Imperative programming grants you too much access to
the underlying memory, allowing you to mutate the memory as you see fit. If not done carefully this can result in hard to find bugs,
moreover manually updating the state in response to events is tedious and distracts from the application logic. Functional
programming, on the end of the spectrum, completely hides the concept of memory forcing you to write your application as a pure
function taking the events and old application state as input and producing the new application state. This forces you to think of
your application in non-interactive terms, and you still have to manually make sure to compute the new state of each computed
affected by the event.

Bindings and Reactive Programming


A binding between two components A and B is an assertion that whenever the state (value) of one component A changes, the state
of the other component B is updated to match the state of A. Bindings can also involve more complex functions, e.g. if C is bound
to A + B, then whenever the value of either A or B changes, C is set to the result of recomputing A + B. This paradigm is actually
most widely used in spreadsheets where the value of a cell is a function of the values of other cells. 

Most GUI toolkits provide some support for simple bindings however they either lack the functionality for specifying bindings
involving an arbitrary function of two or more components, or implementing such a binding requires implementing value
"converter" or "transformer" interfaces in a lower-level language. This is usually so cumbersome that most programmers prefer to
simply drop down to imperative programming.

Functional reactive programming languages are based on the idea of bindings involving arbitrary functions. Admittedly I haven't
tried that many FRP languages, however those which I have tried seem to stick more closely to the traditional functional
programming paradigm of implementing your application as a pure function. Few allow you to implement an application as a set of
distinct nodes with bindings between the nodes.

Enter Tridash
The Tridash language aims to provide a simple and intuitive solution to the State Management Problem, which allows you to think
of your application as an interactive application composed of live stateful, meaning they hold a particular value at a given moment
in time, components called nodes.

Nodes can correspond to purely computational components or other stateful components such as UI elements, the network or the
file system. Bindings between nodes, involving arbitrary functions of other nodes can be declared, using the '->' operator. Examples:
a -> b
a + b -> c

The first example demonstrates a simple binding in which: when the value of a changes, the value of b is updated to it.

The second example demonstrates a binding involve a function of two nodes. When the value of either a or b changes, c is set to
the sum of a and b.

What sets Tridash apart is the free-form manner in which nodes can be declared. There is no main function just a set of declarations.
Bindings can be declared between any pair of nodes.

More than just bindings between nodes, Tridash allows you to treat the bindings as nodes in themselves. Binding to a binding
allows you to control which bindings are active. 

Example:

cond -> (a -> b)

In this example if cond evaluates to true the binding a -> b is active, whereas if it evaluates to false it is as if the binding does not
exist, meaning changes in the value of a will not be propagated to b. This functionality is used to build a unique error handling
scheme, in which bindings are deactivate in the case of an error.

In the next major release you'll also be able to establish bindings between a node and its past states.

The hello example presented earlier can be implemented simply using a single binding declaration.

"Hello: " + name-field.value -> greeting.textContent

where name-field.value  is a node corresponding to the value of the text field UI node and greeting.textContent
corresponds to the content of the UI node in which the greeting is displayed.

Programs as a whole are composed as a collection of a set nodes and bindings between the nodes. Changes in the value of a node,
are automatically propagated to the nodes which are dependent on the node's value. This allows you to focus on the core
application logic rather than the mechanics of propagating changes in state. The benefit of this is that the values of nodes which are
not dependent on each other can automatically be updated concurrently by the underlying framework, without any additional work.

In conclusion the Tridash language presents a new view of your program, as a collection of live inter-connected components, which
provides numerous benefits over the traditional view of your program as a linear sequence of instructions or a linear composition of
functions.

Status
Tridash is currently at version 0.4 however it is still an alpha product and lacks the necessary features for building real-world
applications, such as data-structures and a standard library. Currently only a JavaScript backend is implemented which uses HTML to
provide a user interface. Other backends are planned for a future release.

Tutorials demonstrating the basic functionality of the language. Advanced tutorials and a reference manual are in the works.

Features planned for the next major release:

Data Structures: Lists, Maps, etc.


Macro System
Standard library containing math functions and other commonly used functions.

For installation instructions and tutorials head over to the project's wiki:
https://github.com/alex-gutev/tridash/wiki

What's with the name?


The name is a portmanteau of the words triangle and dash which are the two symbols comprising the bind operator ->, the main
operator in the language. The > symbol somewhat looks like a triangle, right?

License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author


Alexander GutevNo Biography provided
Malta

Comments and Discussions


9 messages have been posted for this article Visit https://www.codeproject.com/Articles/5166094/Tridash-Why-yet-
another-programming-language to post and view comments on this article, or click here to get a print view with messages.

Permalink Article Copyright 2019 by Alexander Gutev


Advertise Everything else Copyright © CodeProject, 1999-
Privacy 2019
Cookies
Terms of Use Web03 2.8.190921.1

Vous aimerez peut-être aussi