From a8dec872871f22d6b8fc3299a46dce2cdc822f89 Mon Sep 17 00:00:00 2001 From: Emil Valeev Date: Sat, 2 Mar 2024 18:18:36 +0500 Subject: [PATCH] feat(spec) --- content/docs/directives/index.md | 2 +- content/docs/spec/_index.md | 13 + content/docs/spec/index.md | 140 ----------- content/docs/spec/runtime/index.md | 6 + content/docs/spec/source-code/index.md | 237 ++++++++++++++++++ content/docs/spec/type-system/index.md | 6 + content/docs/style-guide/index.md | 4 +- public/blog/001_release/index.html | 2 +- public/blog/index.html | 2 +- public/community/index.html | 2 +- ...b663aa25e522674856032060a0f615fe7c1baf.css | 1 + public/docs/about/index.html | 28 +-- public/docs/directives/index.html | 12 +- public/docs/faq/index.html | 12 +- public/docs/index.html | 12 +- public/docs/index.xml | 21 +- public/docs/quick-start/index.html | 12 +- public/docs/spec/index.html | 108 +------- public/docs/spec/index.xml | 32 +++ public/docs/spec/runtime/index.html | 90 +++++++ public/docs/spec/source-code/index.html | 230 +++++++++++++++++ public/docs/spec/type-system/index.html | 90 +++++++ public/docs/style-guide/index.html | 12 +- public/docs/tutorial/01/index.html | 4 +- public/docs/tutorial/02/index.html | 18 +- public/docs/tutorial/03/index.html | 31 ++- public/docs/tutorial/04/index.html | 45 ++-- public/docs/tutorial/05/index.html | 8 +- public/docs/tutorial/index.html | 4 +- public/docs/tutorial/index.xml | 4 +- public/index.html | 20 +- public/index.xml | 53 ++-- public/roadmap/index.html | 75 ++++++ public/sitemap.xml | 14 +- 34 files changed, 964 insertions(+), 386 deletions(-) create mode 100644 content/docs/spec/_index.md delete mode 100644 content/docs/spec/index.md create mode 100644 content/docs/spec/runtime/index.md create mode 100644 content/docs/spec/source-code/index.md create mode 100644 content/docs/spec/type-system/index.md create mode 100644 public/css/main.min.05dc3ab0df5dcbd9902a9767c9b663aa25e522674856032060a0f615fe7c1baf.css create mode 100644 public/docs/spec/index.xml create mode 100644 public/docs/spec/runtime/index.html create mode 100644 public/docs/spec/source-code/index.html create mode 100644 public/docs/spec/type-system/index.html create mode 100644 public/roadmap/index.html diff --git a/content/docs/directives/index.md b/content/docs/directives/index.md index 744c1fd..dc44dc0 100644 --- a/content/docs/directives/index.md +++ b/content/docs/directives/index.md @@ -1,6 +1,6 @@ --- title: Compiler directives -weight: 5 +weight: 4 --- Compiler directives are special instructions for compiler. diff --git a/content/docs/spec/_index.md b/content/docs/spec/_index.md new file mode 100644 index 0000000..099fff2 --- /dev/null +++ b/content/docs/spec/_index.md @@ -0,0 +1,13 @@ +--- +title: Language Specification +weight: 5 +--- + +This is the Language Specification section. It consists of a collection of documents, each detailing a specific part of the language. + +In the "Source Code" section, you will find descriptions of high-level abstractions that users interact with. These are the inputs for the compiler. + +The "Type-System" section provides an in-depth explanation of how the type-system works. This is arguably the most complex part of a compiler's analyzer. It details the different types available and the rules they adhere to. + +Lastly, the "Runtime" section provides insights into how a Nevalang program is executed under the hood. This section is crucial for understanding the operational aspects of the language. + diff --git a/content/docs/spec/index.md b/content/docs/spec/index.md deleted file mode 100644 index 221b0ef..0000000 --- a/content/docs/spec/index.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: Specification (WIP) -weight: 6 ---- - -## Build - -Build is set of Nevalang _modules_. Every module has unique _module reference_. One of the modules is _entry_ module. - -## Module - -Module is a set of _packages_. Every module has its own _manifest file_. - -## Entry Module - -Entry is a root module for compilation algorithm. Every entry module must have _executable_ package. - -## Module Reference - -Entity that refers to a module via _path_ and _version_. - -## Module Manifest - -File that describes which version of language this package supports and list of its _dependencies_. - -## Module Dependencies - -Every module except `std` has dependencies. At least `std`. Dependency is a key-value pair where key is local _alias_ for module and value is a _reference_. - -## Package - -Package is a set of _files_ located in the same directory. Name of the package is the path to its directory from module's root. All _entities_ that exist in a single package must have unique names. - -## File - -File is a set of _import declarations_ and _entity definitions_. - -## Import Declarations - -Imports are a map where key is file-level alias and value is an Import Declaration. Import Declaration consist of module and package names. Module name matches existing alias in current module's manifest's dependencies section. - -## Entity Definitions - -Entity is language abstraction for writing programs. Entities are either _private_ or _public_. There are four _kinds_ of entities (from simple to complex): - -1. _Type Definition_ -2. _Interface Definition_ -3. _Constant Definition_ -4. _Component Definition_ - -## Visibility Scope - -Entities that are _private_ cannot be imported from other packages. _Public_ on the other hand can be imported. Entities are private by default unless special modificator is explicitly used. - -## Type Definition - -Type definition consist of an optional list of _type parameters_ followed by optional _type expression_ that is called _body_. Type definition without body means _base_ type. - -## Base Type - -Type definition without a body. Such type definition assumes that compiler is aware of existing this type and knows how to handle it. Such types are only allowed inside `std/builtin` package. These are base types in official Nevalang implementation: - -## Type Parameters - -Type paremeter consist of its name that must be unique across all other type parameters in definition and constrant. Constraint is a type expression that is used as _supertype_ to ensure _type compatibility_ between _type argument_ and type parameter. - -## Type Parameters and Arguments Compatibility - -Argument `A` compatible with parameter `P` if there's subtyping relation of form `A <: C` where`C` is a constraint of `P`. If there's several parameters/arguments, every one of them must be compatible. Count of arguments must always be equal to the count of parameters. - -## Type Expression - -There is 2 _kinds_ of type expressions: - -1. Instantiation expressions -2. Literals expressions - -Type expressions can be infinitely nested. Process of reducing the type expression called _type resolving_. Resolved type expression is an expression that cannot be reduced to more simple form. - -## Type Instantiation Expression - -Such expression consist of _entity reference_ (that must refer to existing type definition or type parameter) and optional list of _type arguments_. Type arguments themselves are arbitrary type expressions (they follows the same rules described above). - -## Literal Type Expression - -Special cases that cannot be described in a instantiation form. Their list depends on implementation but examples from official Nevalang are `struct`, `enum` and `union`. - -## Interface Definition - -Interface is a _component_ signature, describing it's input and output format. Interface could be though of as a component without _body_ i.e. without implementation. Interface compatibility is implicit. One should not explicitly spell "implements" and instead just pass dependency into _DI_. Interface as an entity consists of two things: _type parameters_ and an _IO definition_. - -## IO Definition - -IO means Input-Output. IO Object describes input and output port of a (possibly abstract) component. Both inports and outports are maps where key is a name of the port (should be unique across all other ports on the same side) and the value is _port definition_. - -## Port Definition - -Port definition consist of a _type expression_ describing the data-type port expects and is-array flag that describes whether the port is an _array_ or _single_ port. Type expression can refer to interface's type parameters. - -## Single Ports - -Single port is port with one slot. Reference to such ports should not include slot index. - -## Array Ports - -Array port is port with multiple (up to 255) slots. They serve for situations when one need to aggregate data of the same type from several (arbitrary count) sources. - -## Constant Definition - -Constant is an entity that consist of either _message_ or _entity reference_ to other constant. Message can include references to other constants. Constant messages can be infinitely nested. Constants may refer imported constants from other packages. _Components_ are only entities that can refer constants, that are not constants themselves - they can refer to constants via _compiler directives_ and from their _networks_. - -## Component Definition - -Component always has _interface_ and optional _compiler directives_, _nodes_ and _network_. There are two kinds of components: _normal_ and _native_ ones. - -## Native Components - -Component without implementation (without nodes and network) must use `#extern` directive to refer to _runtime function_. Such component called _native component_. Native components normally only exist inside `std` module, but there should be no forced restriction for that. - -## Normal Component - -Normal component is implemented in source code i.e. it has not only interface but also nodes and network, or at least just network. Normal components must never use `#extern` directive. - -### Nodes - -Normal component uses other components and interfaces to create nodes for its network. Those _entities_ are _dependencies_ of a component. Nodes that are instantiated from components are _concrete nodes_ and those that instantiated from interfaces are _abstract nodes_. - -#### Dependency Injection (DI) - -Normal component can have abstract node that is instantiated from an interface instead of a concrete component. Such components needs what's called dependency injection at the instantiation time in order to get them work. I.e. if a component has dependency node `n` instantiated with interface `I` one must provide concrete component that _implements_ this interface. Dependency Injection can be infinitely nested. Component `Main` cannot use dependency injection. - -### Network - -Network is a set of connections. There is 2 types of connections: normal and array-bypass - -### Normal Connection - -Normal connection connects one (in) _port-slot_ to another (out). - -### Array Bypass Connection diff --git a/content/docs/spec/runtime/index.md b/content/docs/spec/runtime/index.md new file mode 100644 index 0000000..c5a30ed --- /dev/null +++ b/content/docs/spec/runtime/index.md @@ -0,0 +1,6 @@ +--- +title: Runtime +weight: 3 +--- + +WIP \ No newline at end of file diff --git a/content/docs/spec/source-code/index.md b/content/docs/spec/source-code/index.md new file mode 100644 index 0000000..4463b72 --- /dev/null +++ b/content/docs/spec/source-code/index.md @@ -0,0 +1,237 @@ +--- +title: Source Code +weight: 1 +--- + +This section provides an overview of Nevalang, focusing on its user and compiler perspectives, excluding the type-system which is covered separately. It doesn't delve into the execution details of Nevalang programs, but rather explores the abstractions present in the source code and their governing principles. + +## Build + +Build is set of Nevalang _modules_. Every module has unique _module reference_. One of the modules is _entry_ module. + +## Module + +Module is a set of _packages_. Every module has its own _manifest file_. + +## Entry Module + +Entry module is a root module for compilation. Every entry module must have at least one _executable_ package. + +## Module Manifest + +File that describes which version of language this module supports and list of its _dependencies_. + +## Module Dependencies + +Every module except `std` has dependencies, at least `std`. Module defines dependencies by specifing dependend module's path and version. Every dependency module can have local alias. + +## Package + +Package is a set of _files_ located in the same directory. Name of the package is the path to its directory from module's root. All _entities_ in a package forms single namespace so they must have unique names across package. An entity can refer to entities described in other files in the same package without _imports_. + +## Executable Package + +Package without _public_ entities and with _main_ component + +## File + +File is a set of _imports_ and _entities_. Unlike package file is not a namespace itself, but imports declared inside one file are not visible inside another. There's no restriction on how one should group entities in files inside a package. + +## Imports + +Imports allow to use entities defined in other packages. Imports declared in one file are not visible inside another. Import consist of _module reference_ and _package name_. E.g. `std:http/net` is an import of package `http/net` from module `std`. Only _public_ entities can be imported. + +## Entities + +Entities are abstractions for creating programs. They are either _private_ or _public_. They are private by default and can be made public by using `pub` keyword. Every entity has name that is unique across the package. Entities are _referenced_ by _entity references_. + +There are four _kinds_ of entities (from simple to complex): + +1. _Type_ +2. _Interface_ +3. _Constant_ +4. _Component_ + +## Entity Reference + +Entity reference consist of an optional package name and name of the referenced entity. Package name can be omitted if entity that we reference either exist in the same package or in `std/builtin`. If entity in current package has the same name as the one in the builtin, then it _shadows_ it. + +## Type Entity + +Type entity (type definition) consist of an optional list of _type parameters_ followed by optional _type expression_ that is called _body_. + +## Base Type + +Type definition without body means _base_ type. Compiler is aware of base types and will throw error if non-base type has no body. Base types are only allowed inside `std/builtin` package. Some base types can be used inside _recursive type definitions_. + +## Recursive Type Definition + +If type refers to itself inside its own definition, then it's recursive definition. Example: `type l list`. In this case `list` must be base type that supports recursive definitions. Compiler knows which types supports recursion and which do not. + +## Type Parameters (Generics) + +Every type paremeter has name that must be unique across all other type parameters in this definition and constrant. + +## Type Parameter Constraint + +Constraint is a type expression that is used as _supertype_ to ensure _type compatibility_ between _type argument_ and type corresponding parameter. If no constrained explicitly defined then `any` is implicitly used. + +## Type Parameters and Arguments Compatibility + +Argument `A` compatible with parameter `P` if there's subtyping relation of form `A <: C` where`C` is a constraint of `P`. If there's several parameters/arguments, every one of them must be compatible. Count of arguments must always be equal to the count of parameters. + +## Type Expression + +There is 2 _kinds_ of type expressions: + +1. Instantiation expressions +2. Literals expressions + +Type expressions can be infinitely nested. Process of reducing the type expression called _type resolving_. Resolved type expression is an expression that cannot be reduced to a more simple form. + +## Type Instantiation Expression + +Such expression consist of _entity reference_ (that must refer to existing type definition or type parameter) and optional list of _type arguments_. Type arguments themselves are arbitrary type expressions (they follows the same rules described above). + +## Literal Type Expression + +Type expressions that cannot be described in a instantiation form. + +## Interface Definition + +Interface is a _component signature_ that describes _abstract component_ - its input and output _ports_ and optional type parameters. Interfaces are used with _dependency injection_ and _abstract components_. + +## Ports + +Port definition consist of a _type expression_ describing the data-type port expects and a flag that describes whether the port is an _array_ or _single_ port. Type expression can refer to interface's type parameters. If no type paremeter given then `any` is implicitly used. + +## Single Ports + +Single port is port with one _slot_. Reference to such ports should not include slot index. + +## Array Ports + +Array port is port with multiple (up to 255) _slots_. Such ports must be referenced either via slot indexes or in _array-bypass connection_ expressions. + +## Constant + +Constant is an entity that consist of either _message_ or _entity reference_ to other constant. Message can include references to other constants. Constant messages can be infinitely nested. Constants may refer imported constants from other packages. _Components_ are only entities that can refer constants, that are not constants themselves - they can refer to constants via _compiler directives_ and from their _networks_. + +## Component + +Component always has _interface_ and optional _compiler directives_, _nodes_ and _network_. There are two kinds of components: _normal_ and _native_ ones. + +## Main Component + +Executable package must have _component_ called `Main`. This component must follow specific set of rules: + +- Must be _normal_ +- Must be _private_ +- Must have exactly 1 inport `start` +- Must have exactly one outport `stop` +- Both ports must have type `any` +- Must have no _abstract nodes_ + +Main component doesn't have to have _network_ but it is usually the case because it's the _root_ component in the program. + +## Native Components + +Component without implementation (without nodes and network) must use `#extern` directive to refer to _runtime function_. Such component called _native component_. Native components normally only exist inside `std` module, but there should be no forced restriction for that. + +## Normal Component + +Normal component is implemented in source code i.e. it has not only interface but also nodes and network, or at least just network. Normal components must never use `#extern` directive. + +## Nodes + +Nodes are things that have inports and outports that can be connected in network. There's two kinds of nodes: + +1. IO Nodes +2. Computational nodes + +IO nodes are created implicitly. Every component have one `in` and one `out` node. Node `in` has outports corresponding to component's interface's inports. And vice versa - `out` node has inports corresponding to component interface's inports. + +Computational nodes are nodes that are instantiated from entities - components or interfaces. There's 2 types of computational nodes: concrete and abstract. Nodes that are instantiated from components are _concrete nodes_ and those that instantiated from interfaces are _abstract nodes_. + +Interfaces and component's interfaces can have type parameters. In this case node must specify type arguments in instantiation expression. + +## Dependency Injection (DI) + +Normal component can have _abstract node_ that is instantiated from an interface instead of a component. Such components with abstract nodes needs what's called dependency injection. + +I.e. if a component has dependency node `n` instantiated with interface `I` one must provide concrete component that _implements_ this interface. + +Dependency Injection can be infinitely nested. Component `Main` cannot use dependency injection. + +## Component and Interface Compatability (Implementation) + +Component _implements_ interface (is _compatible_ with it) if type paremeters, inports and outports are compatible. + +Type parameters are compatible if their count, order and names are equal. Constraints of component's type parameters must be compatible with the constraints of the corresponding interface's type parameter's constraints. + +Component's inports are compatible with the interface's if: + +1. Amount is exactly equal +2. They have exactly the same names and _kind_ (array or single) +3. Their types are _compatible_ (are _subtypes_ of) with the corresponding interface's inports + +Outports of a component are compatible with the interface's if: + +1. Amount is equal or more (this is only difference with inports) +2. Exactly the same names and _kind_ +3. Their types are _compatible_ + +## Network + +Network is a set of connections. Every connection consist of sender-side and receiver-side. Sender and receiver must be _compatible_. There is 2 types of connections: normal and array-bypass. + +## Normal Connection + +Normal connection can have several types of sender-side and receiver-side. + +Sender-side: + +1. _Port address_ (traditional) +2. _Constant reference_ +3. _Primitive message literal_ + +Receiver-side: + +1. List of inport-addresses +2. List of _deferred connections_ + +Sender-side in of a normal connection can also have optional _struct selectors_. + +## Sender-Side Struct Selectors + +If (_resolved_) type of sender-side is _structure_, then it's possible to have selectors in it. Selectors are list of strings, where each element means field in a struct. More than one selector means that there is a structure inside structure. Selectors must be type safe. I.e. it must be possible to "unwrap" structure each time we process next selector. + +## Port Address + +Port Address consist of name of the node, name of the port and optional index of the slot. Slot index must be present only if port address refers to array-port. + +## Constant Reference Sender + +In normal connection not just port address but also reference to constant entity (that must be available in the scope) could be a sender. This works exactly like if there's _emitter_ sender with _bound_ constant. + +## Primitive Message Literal Sender + +This works almost like constant reference sender except instead of referencing some constant we simply use message literal. Only primitive data-types are supported: booleans, numbers, strings and enum members. + +## Array-Bypass Connection + +Connection that connects all slots of some sender with all slots of some receiver. Sender and receiver must both be array-ports. Component is only allowed to bypass it's own inports. Such connection always consist of two port addresses without slot indexes. + +## Bound Constant + +Constant that is referenced inside `bind` compiler directive + +## Compiler Directive + +Special instructions for compiler. Directives that must be supported by the compiler are `#extern`, `#autoports` and `#bind`. + +## Runtime Function Overloading + +Native components pass several arguments to `#extern` directive to utilize overloading. In this case arguments are pairs separated by whitespace, they have form `#extern(t1 f1, t2 f2, ... tN fN)` where `t` is a type and `f` is the name of a _runtime function_. + +Component that uses overloading must have exactly one type parameter (it's name doesn't matter) of type `union`. Types that are referenced inside directive must be members of that union. diff --git a/content/docs/spec/type-system/index.md b/content/docs/spec/type-system/index.md new file mode 100644 index 0000000..7946742 --- /dev/null +++ b/content/docs/spec/type-system/index.md @@ -0,0 +1,6 @@ +--- +title: Type System +weight: 2 +--- + +WIP \ No newline at end of file diff --git a/content/docs/style-guide/index.md b/content/docs/style-guide/index.md index 1e2f236..f755bfc 100644 --- a/content/docs/style-guide/index.md +++ b/content/docs/style-guide/index.md @@ -1,6 +1,6 @@ --- title: Style Guide -weight: 4 +weight: 6 --- The Nevalang style guide outlined in this document sets the standards for organizing and formatting code, designing components, and choosing appropriate names. It's recommended that all programs follow this guide to ensure consistency across Nevalang code, making it easier to read and understand. @@ -38,4 +38,4 @@ Good naming arrives naturally from the development process rather than artificia - **Components**: Use actionable noun with "er" ending if possible. - **Ports**: Use short `lowerCamelCase` up to 5 letters. - **Nodes**: Name nodes similarly to their components/interfaces, but in `lowerCamelCase`. Distinguish multiple instances of the same entity by their meaning. -- **Enums**: Use singular form. E.g. prefer `Day` to `Days` so it's clear that enum represent single value. \ No newline at end of file +- **Enums**: Use singular form. E.g. prefer `Day` to `Days` so it's clear that enum represent single value. diff --git a/public/blog/001_release/index.html b/public/blog/001_release/index.html index 4eddf98..a90fa85 100644 --- a/public/blog/001_release/index.html +++ b/public/blog/001_release/index.html @@ -15,7 +15,7 @@ - + diff --git a/public/blog/index.html b/public/blog/index.html index 0441c1c..45bdf02 100644 --- a/public/blog/index.html +++ b/public/blog/index.html @@ -15,7 +15,7 @@ - + diff --git a/public/community/index.html b/public/community/index.html index 8ad48bb..3333a38 100644 --- a/public/community/index.html +++ b/public/community/index.html @@ -15,7 +15,7 @@ - + diff --git a/public/css/main.min.05dc3ab0df5dcbd9902a9767c9b663aa25e522674856032060a0f615fe7c1baf.css b/public/css/main.min.05dc3ab0df5dcbd9902a9767c9b663aa25e522674856032060a0f615fe7c1baf.css new file mode 100644 index 0000000..0cf0b22 --- /dev/null +++ b/public/css/main.min.05dc3ab0df5dcbd9902a9767c9b663aa25e522674856032060a0f615fe7c1baf.css @@ -0,0 +1 @@ +:root{--bg-color:#ffffff;--bg-secondary-color:#f3f3f6;--color-lightGrey:#d2d6dd;--color-grey:#747681;--color-darkGrey:#3f4144;--color-error:#d43939;--color-success:#28bd14;--grid-gutter:2rem;--font-size:1.6rem;--font-color:#333333;--color-primary:#439ceb;--grid-maxWidth:960px;--font-family-sans:'Nunito', sans-serif;--font-family-mono:monaco, "Consolas", "Lucida Console", monospace}body.dark{--bg-color:#000;--bg-secondary-color:#131316;--font-color:#f5f5f5;--color-grey:#ccc;--color-darkGrey:#777}body{display:flex;flex-direction:column}a:hover:not(.button){opacity:1;text-decoration:underline}header,main,footer{flex-shrink:0}header{position:sticky;top:0;z-index:1000;background-color:var(--bg-color)}header .tabs>a,header .tabs>a:hover{border:none}.tabs>a:hover{text-decoration:underline}main{flex-grow:1}footer{padding:20px 0}.nav{align-items:center}.tabs>a{padding:20px;color:var(--font-color)}.logo{width:63px;height:40px;background-image:url(/images/light_gradient.svg);background-size:cover;background-position:50%}.dark .logo{background-image:url(/images/light.svg)}.banner{display:flex;justify-content:center;height:250px;width:100%}.banner .dark{display:none}.dark .banner .light{display:none}.dark .banner .dark{display:block}pre{border-radius:5px}.tab-panel .tabs a,.tab-panel .tabs a:hover{border-color:transparent}.tab-panel .tabs a.active{border-color:var(--color-lightGrey)}.tab-content>section{display:none}.tab-content>section.active{display:block}.docs-nav{list-style:none;padding-left:0;font-size:1.25em}.docs-nav a:hover{opacity:1;text-decoration:underline}a.theme-toggle:hover{text-decoration:none}.docs-card{display:block;box-shadow:none;border:1px solid var(--color-lightGrey);border-bottom:none;border-radius:0}.docs-card:first-child{border-radius:5px 5px 0 0}.docs-card:last-child{border-bottom:1px solid var(--color-lightGrey);border-radius:0 0 5px 5px}a.docs-card:hover{text-decoration:none}.docs-ul{margin-top:20px;padding-left:0;list-style:none} \ No newline at end of file diff --git a/public/docs/about/index.html b/public/docs/about/index.html index 52ce73d..2332c69 100644 --- a/public/docs/about/index.html +++ b/public/docs/about/index.html @@ -15,7 +15,7 @@ - + @@ -44,7 +44,7 @@

It might not be a big deal, but imagine now dealing with func readBooks(books []Book), and you have to write a loop to convert a list of magazines into a list of books. This kind of nesting can increase indefinitely (imagine, for example, just a list of objects with a list of objects inside), leading to the need to write dozens, sometimes hundreds of lines of code for mapping. In a language with structural typing, we simply don’t need to think about this - the compiler sees that the types are structurally compatible and allows the program to compile.

This mechanism also allows for implementing scope for structure fields without additional functionality, and not just at the package level, but even at the level of an individual component. Simply use a more detailed type internally and provide a less detailed type externally. No mappings required.

-

Where do I start?

+

What’s Up With Visual Programming?

+

Warning: Please note that the visual editor is still on the roadmap.

+

For over 50 years, we’ve been writing and editing text, even though it’s well-known that humans better understand visual information. We need a good general-purpose visual programming language. Yes, visual languages exist, but they are mostly specialized. None of them comes close to the popularity of Python or Java. If we look at the top 20 most popular languages, we won’t find any visual ones.

+

If it’s not obvious why we need a visual programming language, consider the number of visual diagrams we use when designing software. Some might argue that text is also a form of visual language because it consists of glyphs, but we’re specifically talking about node editor-based tools. It’s natural for people to think of processes as boxes connected by arrows. Countless examples support this, not only drawings on boards and notebooks but also the popularity of visual software like Miro and Figma, as well as numerous note-taking apps with graph and canvas views like Obsidian.

+

The problem with these diagrams is that they are static. Today, they may reflect the current state of things (and that’s if we’re lucky), but tomorrow they might not. No matter how hard we try to keep documentation updated, it will never fully capture reality. Code is the only thing that can be truly trusted. Oh, if only these diagrams could be the actual code…

+

The argument that visual programming is less maintainable is simply incorrect. It’s just a different form of data representation. The flow-based approach allows for abstraction in the same way we do with text-based programming. Nevalang has components, packages and modules for that.

+

Okay! Where do I start?

Intrigued? Then welcome to the Quick Start extravaganza!

diff --git a/public/docs/directives/index.html b/public/docs/directives/index.html index 5201dc6..83a140b 100644 --- a/public/docs/directives/index.html +++ b/public/docs/directives/index.html @@ -15,7 +15,7 @@ - + @@ -44,7 +44,7 @@