Click here to Skip to main content
Click here to Skip to main content

Bird Programming Language: Part 1

By , 1 Jan 2013
 

Articles About Bird

Table of Contents 

Introduction

I'm developing this language because I don't find the other languages perfect for everything. C++ is known to be one of the fastest languages, but its syntax (especially header files) and the lack of C# like high level features makes developing slower in my opinion. Debugging can be also hard in C++. But C# is a managed language and it limits low level programming and application performance. 3D graphics is about 1.5-2 times slower in C# than in C++.

I have been working on Bird since March 2010 in C#. It's a strongly typed native language. Its performanceeseems to be competitive with C++ compilers currently and it's going toand it's going to have features from high level languages besides new things. There are many things that I haven't implemented yet, but it can be used for smaller programs. The syntax is similar to C# and C++ with some modification in order to make code smaller and improve readability. I was planning to make a C# parser too, but I stopped working on it for now. I will start working on a new in the future. The libraries are similar to .NET, the basic functions are going to be implemented. So I think it won't be hard to understand.

Requirements for Running a Program

Samples have a C++ equivalent code to compare performance. In order to compile them MinGW, Clang are needed to be installed and set in the PATH variable, but it's optional. Visual C++ compiler usage requires the path to "vcvarsall.bat" in to be set in "Run - VC++.bat" files.

Creating Programs with Bird

The compiler can be run from command line by "Bird.exe" which is in the "Binaries" directory:

Bird.exe -x -nodefaultlib -lBirdCore -entry Namespace.Main Something.bird -out Something.exe

I've made .bat files for the samples, so using command line for them is not needed. The -x means that the compiler should run the output file after it had been compiled. The input files can be Bird files, C, C++ or Object files.

Libraries can be specified by the -l option. Currently the BirdCore and BlitzMax are available that are included by default. The -nodefaultlib disables them. BlitzMax is another programming language, its functions are needed for graphics because I haven't implemented them yet.

Object and archive files also can be the output file to use it in other languages. It can be specified with the -format attribute. These are its possible values:

app Executable file
arc Archive file, it doesn't contain the libraries, they need to be linked to the exe.
obj Object file, only contains the .bird files' assembly. The other files and libraries are not included.

Syntax

A Simple Function

using System

void Main()
    Console.Write "Enter a number: "
    var Number = Convert.ToInt32(Console.ReadLine())
    if Number == 0: Console.WriteLine "The number is zero"
    else if Number > 0: Console.WriteLine "The number is positive"
    else Console.WriteLine "The number is negative"
    
    for var i in 1 ... 9
        Console.WriteLine "{0} * {1} = {2}", i, Number, i * Number

    Console.WriteLine "End of the program"

The indication of code blocks are done based on the whitespaces in front of lines. One scope always have the same number of whitespaces. Colon can be used to make the command able to have the inner block in the same line. The compiler needs to know where the previous expression ends. If there's no expression, like the else statement without if, the colon is not needed.

Functions can be called without brackets, if the returned value is not used. In the for loop the var keyword means the type of i, which is the same as the initial value (1 -> int). The three dots means that the first value of i is 1, and it includes the value at the right side, so the last value is 9.

I was thinking about making able to declare variable without type (or the var keyword), but it could lead to bugs if the name of the variable is misspelled.

Literals

Number literals can have different radix and type. $ means hexadecimal, % means binary. Hexadecimal letters have to be uppercase to distinguish them from the type notation, which is the lowercase short form of the type at the end of number:

$FFb        // An unsigned byte
-$1Asb      // A signed byte
%100        // A binary number

Chained Comparison Operators

I think that this could have been implemented in C languages, because in some cases it can be useful. Each sub-expression runs only once, so it's also faster that making two relation connected with and.

bool IsMouseOver(int x, y, w, h)
    return x <= MouseX() < x + w and y <= MouseY() < y + h

The relation operators can only face to one direction to make them distinguishable from generic parameters.

Aliases

It's similar to the using alias directive in C# and the typedef keyword of C++, but in Bird aliases can be created for everything, even for variables. The order of declaration doesn't matter, so it's possible to do this:

alias int32 = int
alias int64 = long
alias varalias = variable

int64 variable

Tuples

Tuple Basics

Tuples are similar to structs but they don't have name. Unlike .NET tuple, Bird tuples are value types. Tuples are a grouping of named or unnamed values that can have different types. For example:

var a = (1, 2)            // Type: (int, int)
var b = (1, 2f)           // Type: (int, float)
var c = ("Something", 10) // Type: (string, int)

In this case the reference of members are done by the index of it (e.g. a_tuple.0), but they can get a name:

alias vec2 = (float x, y)

const var v = (2, 3 to vec2
const var vx = v.x
const var vy = v.y

These variables can be declared as constant because the compiler interprets (2, 3) as a single constant.

Tuples can be also used to swap the values of variables:

a, b = b, a

Tuples as Vectors

Vector operations are based on tuples. The SSE/SSE2 packed instructions will be emitted by tuple operations instead of vectorization. The Cross function can be written as:

alias float3 = (float x, y, z)

float3 Cross(float3 a, b)
    return a.y * b.z - a.z * b.y,
           a.z * b.x - a.x * b.z,
           a.x * b.y - a.y * b.x 

Vector function will be defined in the Math class, some of them are already implemented. Without using the float3 type, this is how it can be written using unnamed members:

float, float, float Cross((float, float, float) a, b)
    return a.1 * b.2 - a.2 * b.1,
           a.2 * b.0 - a.0 * b.2,
           a.0 * b.1 - a.1 * b.0

Tuple Extraction

It's possible to extract a tuple in a similar way as swapping variables:

float x, y, z
x, y, z = Cross(a, b)

Or if var is used, it can be written in a single line:

(var x, var y, var z) = Cross(a, b)

The var have to be written before all the variable in order to make the compiler able to decide which is an existing variable. E.g. if (var x, y, z) = ...  would be interpreted as three new variable then it wouldn't be possible to refer to an existing y, z.

For Loops

for var i in 0 ... 9
for var i in 0 .. 10

Both loops mean the same. Two dots means that i won't have the value at right, in case of three dots it will have that value.

for var x, y in 0 .. Width, 0 .. Height

This is the same thing as two nested loops. The x goes from 0 to Width-1, the y goes from 0 to Height-1. The loop with y variable is the inner one. The break command exits from both.  It can be also written like this:

for var x, y in (0, 0) .. (Width, Height)

If only one number is specified then it will be the initial or the final value of all variables. So this is the same as the previous:

for var x, y in 0 .. (Width, Height)

If there is two point, it's possible to make a single for loop that runs with all points that are in their rect. In this case the x variable goes from P1.0 to P2.0, the y goes from P1.1 to P2.1:

var P1 = (10, 12)
var P2 = (100, 110)

for var x, y in P1 ... P2
    / Something

The step can be used to specify how much the loop variables are increased. It can be both a scalar or a tuple with the same rules. It adds 1 to i and 2 to j at every cycle. The next loop increases i with 1 and j with 2:

for var i, j in 1 .. 20 step (1, 2)

Other Loops

The while, do-while loop is similar to C languages:

var i = 1
while i < 100
    i *= 2

i = 1
do
    i *= 2
while i < 100

 I created two new that the code can be written smaller with. The repeat does something as many times as specified in the parameter. the cycle makes an infinite cycle.

Structures

Structures can contain fields, methods, constructors, etc. The new operator, if the type is not specified, it creates an object with the same type as it is converted to. In this program it is the return type. The original is the var type that is always automatically changed to another type:

struct Rect
    public float X, Y, Width, Height

    public Rect(float X, Y, Width, Height)
        this.X = X
        this.Y = Y
        this.Width = Width
        this.Height = Height

    public Rect Copy()
        return new(X, Y, Width, Height)

    public Rect Copy_2()
        return new:
            X = this.X
            Y = this.Y
            Width = this.Width
            Height = this.Height

    public float GetValue(int i)
        switch i
            case 0: return X
            case 1: return Y
            case 2: return Width
            case 3: return Height
            default return 0

I would note that there is never need to use the break command at the end of the case block. But I'm not sure that there is need for the switch statement, I never use it, if conditions are much more simple in my opinion, especially in C# where the case block must be leaved with some jumping command.

Strings

The most important .NET functions have been implemented. I haven't made a GC yet, so objects will remain allocated until the application exits. It's not a problem for now.

using System

void Main()
    Console.WriteLine "adfdfgh".PadRight(10) + "Something"
    Console.WriteLine "adfdh".PadRight(10) + "Something"
    Console.WriteLine 
    Console.WriteLine "adfdfgh".Contains("fdf")
    Console.WriteLine "adfdfgh".Contains("fdfh")
    Console.WriteLine 
    Console.WriteLine "adfdfgh".Replace('d', 'f')
    Console.WriteLine "adfdfgh".Replace("d", "ddd")
    Console.WriteLine "adfdfghléáőúó".ToUpper()

Arrays

Reference Typed Arrays

This is how 1D reference array can be declared and initialized:

var Array1D_1 = new int[234]
var Array1D_2 = new[]: 1, 2, 3

var Array1D_3 = new[]:
    1
    2
    3
    
var Array1D_4 = new[]:
    1, 2
    3, 4

The compiler takes into account how many dimension are there before interpreting the initial values. The values can be separated with both brackets and new lines. If it founds one less dimensions than specified, the new lines are dimension separators too. I'm not sure it's good, I may remove it the future because it's a bit ambiguous. But it can be also made with using only brackets.

var Array2D_1 = new[,]: (1, 2), (3, 4)

var Array2D_2 = new[,]:
    1, 2
    3, 4
    
var Array2D_3 = new[,]:
    (1000, 1001, 1002, 1003, 1004, 1005
     1006, 1007, 1008, 1009, 1010, 1011)
	 
    (2000, 2001, 2002, 2003, 2004, 2005
     2006, 2007, 2008, 2009, 2010, 2011)

Fixed Size Arrays

These are value types and stored on the stack. Their type is marked with the size unlike reference arrays (e.g. int[10]). This is how can they be created:

int[5] Arr1 = new
int[5] Arr2 = default

The default keyword is the same as in C#. It's just optional to specify the type if it can be inferred. In this case it is the same as the destination variable. The same thing happens with new, it would be new (int[5])(). The new for value types means the same as default. All values in both arrays are initialized to zero. Initial value can be specified as:

var FixedArr1D = [0, 1, 2, 3]      // Type: int[4]
var FixedArr2D = [(0, 1), (2, 3)]  // Type: int[2, 2]
byte[4] FixedArr1D_2 = [0, 1, 2, 3]

The FixedArr1D_2 array can be declared without an error, because the compiler takes the type of the variable into account before evaluating the initial value.
Fixed size arrays can be converted to reference types with an implicit conversion:

double[] Arr = [0, 1, 2]
Func [0, 1, 2, 3]

void Func(double[] Arr)
    // Something
    
long[], byte[] GetArrays()
    return [0, 1, 2], [2, 3, 4, 5]

Pointer and Length

The notation of this kind of array (or rather tuple) is T[*] (T is a arbitrary type), that is actually a short form of (T*, uint_ptr Length). It can be useful for unsafe programming. I created it because I had to write two variables for the same purpose. Both reference type and fixed size arrays can be converted to it implicitly:

using System

void OutputFloats(float[*] Floats)
    for var i in 0 .. Floats.Length
        Console.WriteLine Floats[i]

void Main()
    OutputFloats [0, 1, 2]

    var Floats = Memory.Allocate(sizeof(float) * 3) to float*
    for var i in 0 .. 3: Floats[i] = i + 10.5f
    OutputFloats (Floats, 3)

Parameters with ref, out

Using ref it's possible to use a parameter as input and output. The out can be used for only output, but it makes sure that the variable gets a value:

using System

void OutputFunc(ref int x)
    Console.WriteLine x
    x++

void Func(out int x)
    x = 10

void Main()
    Func out var x
    OutputFunc ref x
    OutputFunc ref x
    OutputFunc ref x

A variable passed with ref must have a value before the function is called, out parameters must be set to a value before leaving the function. These checks can be bypassed with unsafe_ref.

Named and Optional Parameters

Only parameters that have to be specified are that don't have default value:

// The definition of BlitzMax.Graphics
IntPtr Graphics(int Width, Height, Depth = 0, Hertz = 60, Flags = 0)

Graphics 800, 600
Graphics 800, 600, 32

With named parameters, the earlier parameters are not need to be specified:

Graphics Width: 800, Height: 600
Graphics 800, 600, Hertz: 75

Properties and Indexers

They are marked with colon. Properties are handled as variables, when using them the compiler calls the set and get methods. In case of indexer parameters can be specified too:

class Class
    int _Something
    public int Something:
        get return _Something
        set _Something = value
	
    public int AutomaticallyImplementedProperty:
        get
        set
		
    public int this[int Index]:
        get return Index * 2

    public int NamedIndexer[int Index]:
        get return this[Index]
		
void Main()
    Class Obj = new
    Console.WriteLine Obj[3]
    Console.WriteLine Obj.NamedIndexer[4]

Operator Functions

Operators can be defined for structures and classes that wouldn't allow it by default:

class Class
    int _Something
	
    public static void operator ++(Class Obj)
        Obj._Something++
		
void Main()
    Class Obj = new
    Obj++

Getting the Address of a R Value

Sometimes a parameter have to be passed with a pointer to it. In Bird, the address can be queried from constants and R values too, and it automatically copies to a variable:

using System

/* The constructor of Array class:
   public Array(IDENTIFIER_PTR ArrayType, uint_ptr[*] Dimensions,
                uint_ptr ItemSize, void* InitialData = null) */

int[,] CreateIntArray2D(uint_ptr Width, Height)
    var Obj = new Array(id_desc_ptr(int[,]), [Width, Height], 4)
    return reinterpret_cast<int[,]>(Obj)

int[] CreateIntArray1D()
    const uint_ptr Length = 16
    uint_ptr[*] Dimensions = (new: Pointer = &Length, Length = 1)
    var Obj = new Array(id_desc_ptr(int[]), Dimensions, 4)
    return reinterpret_cast<int[]>(Obj)

The type of [Width, Height] expression is uint_ptr[2], so when it casted to uint_ptr* the compiler have to query the address. So it creates a new variable that will be assigned to [Width, Height] and it gets the address of this variable. It does the same with &Length in the second function. reinterpret_cast basically does nothing, it just changes the type of an expression node like casting a pointer.

Reference Equality Operator

The === and !== operator can be used to compare the references of objects. It does the same thing as the Object.ReferenceEquals. The == can be also used for this, but it can be overwritten with an operator function.

public bool StringReferenceEquals(string A, B)
    return A === B

Higher Order Functions

The type of a function can be marked with ->. At the left side there are the input parameters, at the right side the output parameters. The calling convention and modifiers also can be specified. E.g. birdcall string, object -> int, float. When there are multiple outputs, the return type becomes a tuple. In the future I plan to allow all functions to have multiple output in a similar way.

using System

int GetInt(int x)
    return x + 1
	
int Test((int -> int) Func)
    return Func(2)

void Main()
    var Time = Environment.TickCount
    var Sum = 0

    for var i in 0 .. 100000000
        Sum += Test(GetInt)

    Time = Environment.TickCount - Time
    Console.WriteLine "Time: " + Time + " ms"
    Console.WriteLine "Sum: " + Sum

This little sample shows how it works. I made it in C# too, and these are the performance result with my machine:

Compiler Bird C#
Time 719 ms 2234 ms

Actually it is implemented very simply. Higher order functions are just a tuples of an object and a function pointer (object Self, void* Pointer). The Self member can be null if the function is static. It's possible to create a static function pointer with the static keyword: static int -> float. When a nonstatic function is called, the Pointer member is converted to a function pointer. If the Self is not null, it is also added to the parameters. This is how the Test function is extracted:

int Test((int -> int) Func)
    return if Func.Self == null: (Func.Pointer to (static int -> int))(2)
           else (Func.Pointer to (static object, int -> int))(Func.Self, 2)

To make it run faster, the parameter can be replaced to a function pointer. It runs in 542 ms in this way.

int Test((static int -> int) Func)
    return Func(2)

History

  • 1/1/2013: Higher order functions, stack alignment, and many refactoring
  • 10/11/2012: Scope resolution operator, changed casting operator, the to keyword has the same syntax as is and as operator and it doesn't allow ambiguous code.
  • 22/9/2012: Parameter arrays, better x86 performance
  • 18/8/2012: Implemented stackalloc, pointer and length arrays, new and default without specifying the type, static constructors, checked, unchecked, generic parameters with <> (only at reinterpret_cast)
  • 18/7/2012: Object type casting, boxing, unboxing, is as xor operator, low-level reflection, improved x86 code generation
  • 16/6/2012: Exception handling, try-catch-finally, constants also can be declared inside a function
  • 19/5/2012: Arrays, object initializations, address can be taken of r values, ref, out parameters, added Visual C++ compilation of samples
  • 2/5/2012: Improved performance, identifier aliases instead of typedefs, strings, reference equality operator (===, !==), binary files can be linked into the assembly, changed the name from Anonymus to Bird

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Dávid Kocsis
Student
Hungary Hungary
Member
I've been programming for 7 years. My first big project was a remake of a nice bomberman game called Dyna. When i was little i played a lot with it. Now i'm working on a new programming language.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: My vote of 5memberDávid Kocsis23 Sep '12 - 9:24 
Thank You.
QuestionI am intriguedmemberOleg Shilo22 Sep '12 - 23:59 
As already know you have done some brilliant work. My simple "5" does not even accurately reflect the level of the work you have presented here. And lately it is not so often we have genuine "5-star" articles.
 
But I am even more intrigued with the future of your project. It would be really sad if Bird stays as an impressive experiment only.
 
You hinted that you are planing to develop IDE. Fantastic. Of course you can go with the VS extension but I think a standalone IDE may give you more flexibility (freedom).
 
Also consider building up the Bird community. Do not underestimate the importance of this. Sourceforge, Codeplex, GoogleCode/GoogleGroups they are all good options for this but of course the choice depends on so many things (including licencing).
 
Something tells me that you are already well prepared for the challenges ahead of you.
AnswerRe: I am intriguedmemberDávid Kocsis23 Sep '12 - 9:24 
Thank You. Github seems to be the best for me, but I don't really know them. I haven't decided yet which and how to use.
QuestionBird thoughtsmembermfc10220 Aug '12 - 9:00 
Lots of interesting pieces there .. but have you studied Rexx (and NetRexx in particular)? Many of the same aims.
 
Mike
AnswerRe: Bird thoughtsmemberDávid Kocsis21 Aug '12 - 10:11 
Thanks!
I never heard of Rex . It doesn't seem to be very good for me. Its sintax is not that simple in my opinion for the first look.
GeneralMy vote of 5 [modified]memberpasztorpisti20 Aug '12 - 3:57 
Very nice! If I had more time I would definitely kill some of it to explore the topic of compiler construction. Smile | :) I have a few advices regarding bird and the article: Instead of just listing the language features you should give some more explanation on your design decisions! Your language doesnt seem strongly typed, what was your intention with this? (Do you know the drawbacks of ducktyping?) Who is this language for? For example when you describe the for loop: you give several ways to do it. In my opinion the more ways a language gives you to perform a specific task, the worse the language is! (I hate perl for this simple reason.) The for loop is in general used to iterate over an iteratable object. Its another question what kind of iteratable objects are provided by the language, and what kind of iteratable object can be written by a programmer if its allowed at all. A language should be kept as simple as possible without sacrificing its power! Your syntax remdinds me my favorite scripting language: python, check out how simple its basic syntax is! So in general: give more answers to this question: why? by explaining your desing decisions. This helps you too to find out what is good, and what isnt in practice! You could also write some more about optimization and code generation, not in general, but about your methods that you found out in your journey during compiler construction. Smile | :)

modified 25 Sep '12 - 9:32.

GeneralRe: My vote of 5memberDávid Kocsis20 Aug '12 - 20:37 
Thank You! I will try to follow your advices in the future. You are right about that I should explain more.
 
pasztorpisti wrote:
Your language doesnt seem strongly typed, what was your intention with this? (Do you know the drawbacks of ducktyping?)
Actually it's strongly typed and does type inference to make the unambiguous things take less code. It would be impossible to achive similar performace otherwise.
 
pasztorpisti wrote:
For example when you describe the for loop: you give several ways to do it. In my opinion the more ways a language gives you to perform a specific task, the worse the language is!
I only added a new way to write more for loops in one for the same reason, to make coding take less time and make it simpler. And it seemed to be straightforward for me. A simple for loop is like in Python:
for count in range(1, 11):
    print(count)
 
for var count in 1 .. 11
    Console.WriteLine count
And if you want to write two:
for a in range(1, 4):
    for b in range(1, 4):
        print(a, " * ", b, " = ", a * b)
 
for var a, b in 1 .. 4
    Console.WriteLine a + " * " + b + " = " + (a * b)
To be honest I don't find it bad, in the sample there was "for var x, y in P1 .. P2" (where P1 and P2 are (int, int)), In my opinion it's easy was to go through all cordiantes between two points. But there was some things that were smaller, but I removed, because it was bad.
 
pasztorpisti wrote:
You could also write some more about optimization and code generation, not in general, but about your methods that you found out in your journey during compiler construction. Smile | :)
It's hard to write about code generation in detail and clearly. It's the most complex part of it, and sometimes even I don't know how something works exactly. I have to look at the code to tell it. And I'm less willing to write than developing. But I'll keep in mind to update it too.
GeneralRe: My vote of 5memberpasztorpisti20 Aug '12 - 21:14 
Dávid Kocsis wrote:
Actually it's strongly typed and does type inference

My bad, I always assume ducktyping when it comes to type inference. For some reason I don't like it because often makes reading others' code difficult when the assigned expression is a variable or function call or whatever that doesn't help you to find out the type. On the other hand you still have to write there the "var" keyword that makes some noise, is that there to speed up parsing? (Another design decision you should write about Smile | :) )
Dávid Kocsis wrote:
I only added a new way to write more for loops in one for the same reason, to make coding take less time and make it simpler. And it seemed to be straightforward for me. A simple for loop is like in Python:

for count in range(1, 11):
    print(count)
 
for var count in 1 .. 11
    Console.WriteLine count

In older python versions the range() function returns a list object that contains numbers from 1 to 11 (with default steps = 1), the newer python versions return a generator function. The common in the two python solutions is that both the list and the generator function is iterable, and the language gives you the opportunity to write your own iterable objects - same is true some other high level languages like C# and java. For example you can use for (Animal x : animals) in java to iterate over a arbitrary container instance that contains Animals. Your for loop is OK, it just isn't a general one that would be awesome in case of iterable containers.
Dávid Kocsis wrote:
It's hard to write about code generation in detail and clearly. It's the most complex part of it, and sometimes even I don't know how something works exactly. I have to look at the code to tell it. And I'm less willing to write than developing. But I'll keep in mind to update it too.

Unfortunately I share the same opinion about writing/developing. Smile | :) I have quite a few article ideas but I'm hell lazy to actually start putting together an article. Still, if you take the trouble to write about it then try to pick a few techniques that are very useful still easy to implement. Depending on the verbosity you use that topic can fill a whole new article.
GeneralRe: My vote of 5memberDávid Kocsis21 Aug '12 - 10:02 
pasztorpisti wrote:
My bad, I always assume ducktyping when it comes to type inference. For some reason I don't like it because often makes reading others' code difficult when the assigned expression is a variable or function call or whatever that doesn't help you to find out the type. On the other hand you still have to write there the "var" keyword that makes some noise, is that there to speed up parsing? (Another design decision you should write about Smile | :) )
As I know ducktyping means that the method is resolved at runtime, but it's resolved at compile time in my language. A good IDE shows the type of a variable when you move the cursor over it. I plan to do the same, if I ever get there. var is not to speed up parsing, it's to avoid bugs when variable's name is misspelled. I was thinking about allow not using it, but I'm not sure it would be good.
 
pasztorpisti wrote:
In older python versions the range() function returns a list object that contains numbers from 1 to 11 (with default steps = 1), the newer python versions return a generator function. The common in the two python solutions is that both the list and the generator function is iterable, and the language gives you the opportunity to write your own iterable objects - same is true some other high level languages like C# and java. For example you can use for (Animal x : animals) in java to iterate over a arbitrary container instance that contains Animals. Your for loop is OK, it just isn't a general one that would be awesome in case of iterable containers.
Iterators will be implemented later, but if there wouldn't be a counter for loop, it would make performance much worse.
 
pasztorpisti wrote:
Still, if you take the trouble to write about it then try to pick a few techniques that are very useful still easy to implement. Depending on the verbosity you use that topic can fill a whole new article.
I don't know how will I do it yet, it won't be done so soon probably.
GeneralRe: My vote of 5memberpasztorpisti21 Aug '12 - 10:46 
Good points. Incorporate them to the article! Smile | :)
 
Cheers,
pasztorpisti
GeneralRe: My vote of 5memberDávid Kocsis21 Aug '12 - 20:09 
Okey, Thanks
QuestionC# is nativememberGerhardKreuzer24 Jul '12 - 2:10 
Hi,
C# is a native language as long you use the program more than once, which is a quite common program usage pattern, I guess.
During the first usage, the IL code is compiled JIT (just in time) and from now on, it is native as each other language.
The libs were partly written in assembler, so I think, you hardly can get a faster program.
Of course, you can left beside all runtime checks, as C++ do (or even never has), but is this really a wise decition?
 
With best regards
 
Gerhard
AnswerRe: C# is nativememberDávid Kocsis24 Jul '12 - 3:45 
Hi!
 
Every language that runs on the .NET framework is called managed (http://en.wikipedia.org/wiki/Managed_code[^]).
I may try to include C# in the performance tests, but it's not as simple as C++. I have no idea how to import functions without performance impact. The best way seems to be a wrapper library in C++/CLI.
Many people say that C++ is the fastest language, but I have to admit that C# performs well sometimes, even though its disassemly looks really bad. Game developers use C++, DirectX for C# is also much slower. The best would be if high-level wouldn't mean restrictions to low-level usage and performance.
Runtime checks in my language will be switchable, so it won't slow down anything and doesn't make debugging a nightmare.
 
Best regards,
David
QuestionC++ is slow?memberVitaly Tomilov18 Jul '12 - 8:54 
Well, that's a news...
 
You obviously didn't use it enough, making such statements. To develop fast in C++ you need to use professional frameworks. And, of course, things like MFC or whatever Microsoft bundles VC++ with isn't good at all.
 
What is good - Qt[^] It offers a professional multi-platform framework that's more powerful than .NET 4.
Let's agree to disagree!
Boris the animal Just Boris.

AnswerRe: C++ is slow?memberDávid Kocsis18 Jul '12 - 10:59 
I know that Qt is powerful, but a library can't make C++ neat. I wouldn't be able to use Qt if I would develop Bird in C++ because basically all I need is simple file I/O (with little exaggeration). Also, IMHO Qt for .NET could be even more powerful than in C++.
GeneralRe: C++ is slow?memberFabian Tamp22 Jul '12 - 20:03 
Qt does make C++ neater, in the sense that it's higher level, but it's still a library on top of a programming language. Also, I've personally found that Qt suffers from the "Jack of all trades, master of none" problem that plagues most cross-platform software - whilst it works to a standard on all platforms, it doesn't really shine on any of them.
GeneralRe: C++ is slow?memberDávid Kocsis22 Jul '12 - 22:56 
I meant it can't make better the language itself, but it obviously can reduce code lines where it can be used. The best library or language depends on the task and none of them are perfect for everything. And it also depends on the developer's taste and knowledge. It's useless to argue on which is the best.
GeneralThanks for sharingmemberSomnath_Mali17 Jun '12 - 20:15 
Thanks for sharing Smile | :)
GeneralDownloadmemberDávid Kocsis16 Jun '12 - 19:55 
If the download link doesn't work, you can use this: https://dl.dropbox.com/u/28475953/Bird.zip[^]
GeneralMy vote of 5memberSoMad16 Jun '12 - 19:04 
This is very impressive work!
I will be watching your updates to Bird and the article.
 
Thumbs up.
Soren Madsen
GeneralRe: My vote of 5memberDávid Kocsis16 Jun '12 - 19:50 
Thank You
QuestionNamespacesmemberumlcat25 May '12 - 7:17 
Very Good.
 
I suggest add a new required namespace for each file, and do not. Otherwise, your language may get in the same problem as PHP, C, C++, where namespaces where added later.
 
------
HelloByrdExample.byrd
------
namespace HelloByrdExample
 
  rem these go inside the namespace, not outside
  using System
 
  public void Main()
    print "Hello Little Byrd,"
    print "Please sing a song"
------
 
Cheers.
AnswerRe: NamespacesmemberDávid Kocsis26 May '12 - 21:52 
Thanks. The libraries have namespaces like .NET, but samples don't have because it wouldn't be used anywhere else. The problem is that the Main function must be outside of any namespace not just because Bird would have to find it, it would also mean an unresolved external symbol error. I'll correct this in the future, but there are lot of things to do now.
AnswerRe: NamespacesmemberDávid Kocsis18 Jul '12 - 6:08 
I implemented it
QuestionMy vote of 5memberFilip D'haene19 May '12 - 0:45 
Amazing and excellent!!!
 
Thanks for sharing. Smile | :)
AnswerRe: My vote of 5memberDávid Kocsis19 May '12 - 0:48 
Thank You
QuestionWhat is the future?memberPascal Ganaye4 May '12 - 1:36 
Do you plan to be self hosting[^]?
I believe you need to write a compiler that compile itself to enter the Compiler writer guild.
Personally I would rather see a language that uses multi-cores in a more elegant way that what has been done so far.
AnswerRe: What is the future?memberDávid Kocsis4 May '12 - 18:06 
Yes, when I make an IDE, which would be written in my language, I'll need the whole compiler to be in the same language for code-completion, debugging.
I haven't been thinking of threading, what would you like to be changed about it?
GeneralRe: What is the future?memberPascal Ganaye5 May '12 - 6:49 
You'll have to excuse my rambling it is saturday and my neighbour offered a couple of vodka at lunch time.
 
This is fuzzy ideas.
Let me rewind.
Here is my caricature of the history of computing:
 
On the first day there was code machine.
In code machine the language reflect very closely the processor hardware.
There is very little abstraction.
You can do what you want and as you wrote run anything jump everywhere. Freedom is king here.
There is many trade-off though. You can run instruction that the processor would not understand, break the stack, inadvertently modify the code your running.
 
On the second day there was C
In C, it was quite obvious what was added :class, loops, expressions...
Your stack is much safer, and typically your jumps are too.
But there is a trade-off. You lose the control over which register is used and how you want to pass parameters between different pieces of code.
At about the same time came the memory allocation and deallocation routines (malloc and mfree).
Those two functions came and allowed us to have any number of objects in memory depending on the need.
There was a trade-off though, you could not guarantee where the objects are anymore. And you had to remember to free the object. This allowed us to go out of memory much more easily. It made dangling pointers much more common too.
 
On the third day there was Java and C#
Those languages arrived quite a bit later, they brought some more abstractions, and typically run in a Virtual Machine. But their real big difference with C is that every byte you read on write in memory is bound-checked. The stack is safe the memory too.
To get there, there is a big trade-off though. Both these language require full memory management and garbage collectors. This abstraction removed the liberty to free the objects at a deterministic time.
 
On the fourth day there will be multiple cores
We are starting to routinely see machines with 8 cores or more, at this stage it doesn't really matter if your compiler make a program run twice as slow if it also manage to use multiple cores.
 
I don't know how this will be architectured but I have a feeling that as we lost memory allocation on day 3, on the next day we'll lose multi-thread synchronization.
Typically today we have to remember to use synclocks and we get deadlocks.
To me this is strangely reminiscent to when we had to remember to use mfree and where having memory leaks.
 
Perhaps objects could be automatically synchronized
 
/*synchronized*/ class myobject
{
  // any method call to this object is locked or perhaps queued
}
 
This would probably come with a ton of problems.
I don't really know what the future will bring, I am not clever enough for that, but I think the next abstraction will be the processor core.
The compiler will use more of it.
This will probably come with some language limitation.
A bit like we lost fixed memory allocation, then deterministic destructors we'll have to lose some things to allow the compiler to do a better job.
 
From what I hear, not that I understand it might have to be that classes will become immutable and all execution path will be finite no exception.
I am way out of my depth there.
 
Because you sound like a smart guy I just wondered what was your thoughts about it.
 
In a more realistic time frame. Do you have a plan to implement some memory allocation / garbage collection?
GeneralRe: What is the future?memberDávid Kocsis5 May '12 - 10:21 
It can be the basic of a future's language. The problem is the lot of memory copying and object allocation, it has to be fast. For example in a game when a player's position is changed, a new object have to be created just to change a variable. The good is that immutable object wouldn't allow reference cycles so a simple reference counting is enough for garbage collection. I can't immagine how a software would look like written in a language like this.
 
Currently I'm working on the C# language and referece arrays. Maybe I'll also make exceptions, etc. before the garbabe collector. It's not a problem if an object remains unallocated for now.
GeneralRe: What is the future?memberKenBeckett7 May '12 - 9:20 
I really think it would be a lot smarter to leverage the .NET platform, which includes an optimized GC, a full IDE, massive libraries, and tons of other things that you need. It is specifically designed from the ground up to support new languages like Bird. You should base your language on .NET to start, then you can always make an independent version later on if usage actually takes off. Also, contrary to another post of yours, .NET really is cross-platform using Mono. It's not perfect, but it works and there is source code.
 
I also don't understand why you seem to be working on a C# compiler... why? You should bootstrap your new language by writing it in itself rather than another language - this will force you to make it a full featured language that can do everything you need to compile it with itself. Writing one language is a big enough task, but C# is a VERY complex language - read the (500 page) C# 4.0 spec carefully at least twice before you start. If you're aiming for C# 4.0, that is a HUGE effort to replicate - it's a very complex language with tons of interactions between features. Type inference and method overload resolution are each easily many months of work to get right (I know what I'm talking about - I've done them). Also, do not assume that big spec is 100% right - it's not. A few things are missing and/or just incorrect.
 
Anyone who creates their own computer language is crazy. But, if they don't leverage .NET and try to create their own C# compiler at the same time, they're a lunatic. Smile | :)
GeneralRe: What is the future?memberDávid Kocsis26 May '12 - 21:21 
The real reason for not using .NET is that Bird would be almost the same as C# with only differences in syntax. The native code generator makes Bird better than .NET languages. It makes the assembly faster and enables things that managed languages not. It's true that it needs more work, but I started with this and don't want to begin a new code generator which would also take time.
 
It's not a big thing to make a C# compiler which knows that Bird knows. Amost everything would be the same except some recognizers. It means about just 1500-2500 lines of code. But I would be able to compile my compiler in the future and my C# compiler would have the same performace as Bird and features like tuples. I don't want to follow the specification strictly, it's enough for me if it can compile Bird. (It doesn't let me to do a lot of things in a different way) It would also mean less problem to use Bird through its C# compiler for those who know C# or just don't like the indication of scopes by indenting.
GeneralMy vote of 5memberPetr Abdulin2 May '12 - 20:26 
While I still doubt, that such new language is really needed and will be used widely (more than 1 person Smile | :) ), I'm impressed with your skill! An compiler and assembly generation logic is useful enough by itself for someone who want to learn this areas. Thank you for sharing.
GeneralRe: My vote of 5memberDávid Kocsis4 May '12 - 17:42 
Thanks for the vote. I'm not sure too, the most people may not want to learn a new language but I hope there'll be some people who think it's worth learning it.
GeneralMy vote of 5memberpaladin_t2 May '12 - 15:24 
Looks very interesting and powerful. Great job! I've some simple questions: what's the purpose for you to develop this language; could I integrate it with other languages like C/Cpp and make extended APIs for it?
GeneralRe: My vote of 5memberDávid Kocsis2 May '12 - 19:15 
Thank You. The main purpose was to use for my projects. I didn't expect that it takes so much time.
Currently only functions and variables can be integrated. C++ classes are harder to implement, I wasn't planning to make it, but COM interfaces will be supported.
QuestionNice loopsmemberPascal Ganaye2 May '12 - 11:55 
Ever since you started to write articles here, I have been very impressed by your project.
The courageous choice you took to write everything from scratch could seem reckless at first. But you appear to make it so much seed improvement that it seem to make sense. I am envious of your talent.
AnswerRe: Nice loopsmemberDávid Kocsis3 May '12 - 6:27 
Thank You
QuestionNice Jobmembervbfengshui2 May '12 - 11:08 
Very impressive effort!
 
I like most of what you've got going, but I have to admit, I've never been a fan of "indenting to indicate code blocks". I believe Python is that way as well. I much prefer blocks to be explicitly delineated.
 
Still, the rest of the syntax you've cooked up seems to flow very nicely. Compilers are hard, language design even harder.
 
This is pretty slick.
vbfengshui

AnswerRe: Nice JobmemberPeter_Olson2 May '12 - 11:40 
Indentation is a form of explicit delineation.
GeneralRe: Nice Jobmembervbfengshui2 May '12 - 12:08 
I'd tend to disagree on that point. To me, any "meaning" implied by indentation is more implicit than explicit.
 
My point being I find languages that do that to be harder to work with on a general basis. You just have less leeway with how you can lay out code for various purposes.
 
But, hey, in the end, it's his language. Virtually everything else about it looks +really+ good, from a purely language aesthetics standpoint, in any case.
 
just my 2c
vbfengshui

GeneralRe: Nice JobmemberPIEBALDconsult2 May '12 - 12:39 
Just not a good one. Big Grin | :-D
AnswerRe: Nice JobmemberPIEBALDconsult2 May '12 - 12:36 
vbfengshui wrote:
never been a fan of "indenting to indicate code blocks".

 
I agree; all whitespace (other than within string literals I suppose) should be collapsable to a single SPACE without affecting the meaning of the code.
AnswerRe: Nice JobmemberDávid Kocsis2 May '12 - 19:35 
Thank You. I wanted to make a C# compatible, because in the future i want to use it for self-compiling (there's still a long way to it). Maybe within some updates the samples will have a C# like version.
QuestionSooo...memberPIEBALDconsult2 May '12 - 10:31 
Bird is the word now?
 
Big Grin | :-D
AnswerRe: Sooo...memberZac Greve2 May '12 - 10:58 
No. Mums the word!
public class SysAdmin : Employee
{
 
     public override void DoWork(IWorkItem workItem)
     {
          if (workItem.User.Type == UserType.NoLearn){
             throw new NoIWillNotFixYourComputerException(new Luser(workItem.User));
          }else{
               base.DoWork(workItem);
          }
     }
 
}

AnswerRe: Sooo...memberDávid Kocsis2 May '12 - 18:56 
I've changed it because Anonymus is already used by the hacker group, and because I write it everywhere with Hungarian spelling. It's very hard to find a good name.
QuestionWhy create yet another compiler?memberAbu Mami23 Apr '12 - 23:10 
Why? Because this one is freakin' cool! Wish I had the time to play with this. Nice job! Got my 5.
AnswerRe: Why create yet another compiler?memberDávid Kocsis24 Apr '12 - 1:44 
Thank You
QuestionWhat about writing a compilermemberJacek Gajek20 Apr '12 - 10:22 
What about writing a compiler to an existing language? It would be nice to have a C# or a Python with access to their's frameworks, but a compiled assembly would be actually compiled (not some bytecode, IL etc.) and wouldn't need any runtime at all. This is possible if a required part of a runtime would be somehow injected to an excutable file... Just an idea.
Greetings - Jacek

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 1 Jan 2013
Article Copyright 2011 by Dávid Kocsis
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid