Programmiersprache Ü. Einführung, Motivation zu schaffen, Ziele

Einführung


Seit 2016 (mit Unterbrechungen) entwickle ich meine eigene Programmiersprache. Der Name dieser Sprache ist "Ü". Warum Ü? Weil ich einen Namen mit einem Buchstaben wollte und alle Buchstaben aus dem Satz von AZ bereits vergeben sind.

Dieser Artikel hat die Aufgabe, die Öffentlichkeit mit dieser Sprache vertraut zu machen, um einen allgemeinen Eindruck davon zu vermitteln. Der Artikel beabsichtigt nicht, die Sprache vollständig zu beschreiben. Eine vollständigere Beschreibung der Sprache, falls erforderlich, wird in den folgenden Artikeln gegeben.

Warum brauchen wir eine andere Sprache?

Ich untersuchte eine Reihe vorhandener statisch typisierter, mehr oder weniger bekannter Sprachen und kam zu dem Schluss, dass keine von ihnen vollständig zu mir passt. Alle von ihnen haben "fatale" Mängel.

Spezifische Punkte:

  • C - zu niedrig und unsicher
  • C ++ - erbte viele Low-Level-Fehler, neue Möglichkeiten, sich in den Fuß zu schießen, mangelnde Reflexion
  • D - Garbage Collector, separate Referenztypen
  • Java ist ein Garbage Collector, auf alle zusammengesetzten Typen wird verwiesen, starke Bindung an eine virtuelle Maschine. Vieles davon gilt auch für JVM-basierte Sprachen.
  • C # - Fehler ähneln Java
  • Rust - die Notwendigkeit, Links explizit zu nehmen und explizit zu dereferenzieren, (subjektiv) die Gefahr eines Ansatzes, wenn alles ein Ausdruck ist und ein Ergebnis zurückgibt, das Vorhandensein eines expliziten Hinweises auf die Einhaltung des Protokolls, das Fehlen von Vererbung
  • Go - Garbage Collector, fehlende Vorlagen
  • Swift - Referenztypen, die explizit die Einhaltung des Protokolls angeben müssen

Nachdem ich die Unvollkommenheit aller oben genannten Sprachen entdeckt hatte, entschloss ich mich, meine eigene zu erschaffen, ohne, wie mir scheint, alle Mängel.

Allgemeine Informationen


Ü ist eine kompilierte, statisch typisierte Sprache mit starker Typisierung. Die Sprache enthält freie Funktionen, Strukturen, Klassen, Methoden für Strukturen und Klassen. Bestehende Arten von Typen - grundlegend, strukturell (Strukturen, Klassen), Arrays konstanter Größe, Tupel, Aufzählungen, Zeiger auf Funktionen. Klassen können an der Vererbung teilnehmen und haben virtuelle Funktionen. Die Sprache unterstützt Vorlagen, es gibt Vorlagen für Klassen und Strukturen, Aliase von Typen, Funktionen und Methoden. Es gibt eine Überlastung von Funktionen und Operatoren (mit einigen Einschränkungen).

Die Sprache unterstützt Destruktoren für Klassen und Strukturen. Destruktoren werden zum Verwalten von Ressourcen einschließlich Speicher verwendet.

Was ist schon da


Implementierter LLVM-basierter Compiler. Der Compiler unterstützt alle Plattformen, die LLVM unterstützen. Der Compiler weiß noch nicht, wie man rein ausführbare Dateien erstellt, kann jedoch Objektdateien, Assembler-Code, Binär- oder Text-llvm-Code generieren. Es ist möglich, mit C-Code zu kommunizieren. Es gibt ein Dienstprogramm, das das Schreiben von Ü-Headern für C-Bibliotheken erleichtert.

Ziele und Vorgaben


Die Sprache wird so erstellt, dass die maximale Anzahl typischer Fehler in der Kompilierungsphase erfasst wird. Entscheidungen zur Sprachgestaltung werden in erster Linie auf der Grundlage dieser Aufgabe getroffen. Das zweite Ziel ist die (relative) Leichtigkeit, Programme zu schreiben und sie zu lesen.

Die Sprache enthält keine Konstrukte, die das Schreiben von fehlerhaftem Code provozieren könnten, und enthält auch keine Funktionen, die das Verständnis der Vorgänge im Programm erheblich erschweren könnten.

Trotz der oben genannten Punkte kann das Problem der Leistung nicht ignoriert werden. Daher werden zum Nachteil der Leistung keine Entscheidungen zum Sprachdesign getroffen.

Schauen wir uns also an, welche Momente in Ü den angegebenen Zielen entsprechen.

Typ System


Im Gegensatz zu C ++ gibt es in Ü keine Zeiger und Referenzen als Typen. Es gibt überhaupt keine Zeiger, es gibt Links, sondern nur als Stack-Links, Funktionsreferenzargumente, Referenzfelder. Außerdem sind mut / imut-Modifikatoren nicht Teil eines Typs, sondern Teil einer Variablen, Referenz, eines Funktionsarguments oder eines Feldes.

Dank dieser Vereinfachung ist es besser zu verstehen, wo sich welcher Typ befindet, insbesondere im Code für Boilerplates. Es gibt keine Zweifel, ob ein Link oder eine Variable deklariert wird, Zweifel infolge von typeof (Analogon von decltype aus C ++), Zweifel an konstant / nicht konstant.

Die Kehrseite dieser Vereinfachung ist die Notwendigkeit einer getrennten Verarbeitung von Konsistenz und Links in Vorlagen. Dies erhöht jedoch die Klarheit, wenn der Konstanzparameter als explizit separates Argument an die Vorlage übergeben wird.

Initialisierer


Es ist unmöglich, eine Variable zu deklarieren und nicht zu initialisieren. Jedes Byte der deklarierten Variablen muss initialisiert werden.

Grundlegende (und einige andere) Typen erfordern eine obligatorische Initialisierung:

var i32 x= 22, y(12345);

:

struct Vec{ f32 x; f32 y; }
...
var Vec v{ .x= -56.1f, .y= 42.0f };
var Vec v_uninit; //  

, :

struct Vec
{
	f32 x; f32 y;
	fn constructor()
	( x= 0.0f, y= 0.0f )
	{}
}
...
var Vec v; //  

, .

, :

struct Vec
{
	f32 x= 0.0f;
	f32 y= 0.0f;
}

, [] , :

var [ i32, 4 ] a[ 1, 1, 3, 4 ];
var tup[ i32, f32 ] t[ 8, 0.5f ];
var [ f32, 16 ] a_uninit; // ,     .
var[ i32, 3 ] aa[ 0, 1 ]; // ,  

C++, , . , , — .

. , , — . this, - /, :

struct Vec
{
	f32 x; f32 y;
	fn constructor()
	( x= y, y= 0.0f ) // ,  «y»   
	{}

	fn constructor( f32 val )
	( x= val, y= x ) // . «x»         «y»
	{}
}


. , , . .

:

var i32 mut x= 0;
var i32 &mut ref0= x;
++x; // ,        
var i32 &imut ref1= x; // ,    , . .    

:

var i32 mut x= 0;
var i32 &imut ref0= x;
var i32 &mut ref1= x; // ,    ,     

:

var i32 mut x= 0;
var i32 &mut ref0= x;
var i32 &mut ref1= ref0; //  , . .       ,     

:

fn Mutate( i32 &mut x, i32 &mut y );
...
var i32 mut x= 0;
Mutate( x, x ); // ,          

. C++

std::vector<int> vec;
vec.push_back(1);
int& ref= vec.front();
vec.push_back(2); // ,  ref        

Ü :

var ust::vector</i32/> mut vec;
vec.push_back(1);
var i32 &imut ref= vec.front();
vec.push_back(2); // ,      vec,      


( ). — polymorph, interface, abstract . . , .

:

  • . , , .

    :

    class A interface
    {
    	fn virtual pure Foo(this);
    }
  • . . . , this, , . . . abstract call, , , C++.

    :

    class A abstract
    {
    	fn virtual pure Foo(this);
    	fn virtual Bar(this){}
    	i32 x= 0;
    }
  • . . . - , .

    :

    class A interface
    {
    	fn virtual pure Foo(this);
    }
    class B : A
    {
    	fn virtual override Foo(this){}
    }
  • . , , .

. .

fn virtual pure Foo(this); //    .      ,        ,   .

fn virtual Foo(this){} //     .   ,      .

fn virtual override Foo(ths){} //   ,    .         ,   .

fn virtual final Foo(this){} //   ,     .         ,   .  -    ,   .


2019— , , Ü . . , , , , .

:

fn Foo( i32 mut x ) : i32
{
	while(x  < 100 )
	{
		x+= 10;
		continue;
		x+= 20; // ,  
	}
	return x;
	++x; // ,  
}

:

fn Foo( i32 x ) : i32
{
	if( x < 10 ) { return 0; }
	else if( x > 100 ) { return 1; }
	// ,     
}

else , return .

, - , halt ( ). , , , return.


. , (. ). () .

:

struct CallableObject
{
	i32 &mut x;
	op()( mut this )
	{
		++x;
	}
}
...
var i32 mut x= 0;
var CallableObject mut obj{ .x= x };
auto thread= ust::thread_create( move(obj) );
++x; // ,   «x»,        «thread»
++ obj.x; //  

- , , - , .

(mutable C++), . . . , - , .

, ? — shared_ptr_mt . , , lock_mut() lock_imut(), . « , ».

:

struct Incrementer
{
	ust::shared_ptr_mt_mut</ i32 /> ptr;
	op()( mut this )
	{
		auto mut lock= ptr.lock_mut(); //   «lock»  
		++lock.get_ref();
	}
}
...
var ust::shared_ptr_mt_mut</ i32 /> ptr(0);
var size_type mut i(0);
var ust::vector</ ust::thread</Incrementer/> /> mut threads;
while( i < size_type(64) )
{
	var Incrementer incrementer{ .ptr= ptr };
	threads.push_back( ust::thread_create(incrementer) );
	++i;
}
threads.clear(); //      .
halt if( ptr.lock_imut().get_ref() != 64 ); // ,   ,  

, , . . «shared». , , , - , «shared».


. , , constexpr . , .

, Ü, - , C.


C++, (=, +=, *= . .) , , . ++ –.

:

if( x = 0 ) {}
x++; //     ++
x += x += x; // ,  +=  
x+= x++ + ++x; //      

. void, .

, , . :

auto a = select( condition ? x : y );

select .


. . . .

? , - :

  • . - , , .
  • . . - NullPointerException - , - . , , . . .
  • . , , , . - - , . , .
  • . , , .

, , ?

, . . «» , , std::optional/std::variant C++ Option/Result Rust.

, -, , halt. ( Ü ) , , , .


, - . , import, , . C++, , .

. , *.cpp *.hpp C++.


, , , .

, , . , , , . , - , .




, , .

.

, . . , .

Source: https://habr.com/ru/post/de465553/


All Articles