Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » My new programming language.

This thread is locked; no one can reply to it. rss feed Print
My new programming language.
Jonny Cook
Member #4,055
November 2003

I made a little scripting language once, however it was more just a fun learning experience than a real tool. But now at least I feel like I understand how hard it is to do. So good luck! It sounds like a very ambitions project.

The face of a child can say it all, especially the mouth part of the face.

anonymous
Member #8025
November 2006

bamccaig said:

What exactly can a function that can't assign to anything even do? ??? Unless I'm missing something, you're pretty much limited to returning some expression... :-/ If nothing in your function or the functions it can call can do any assignment then you're pretty much just making a wrapper that does nothing. :P

I suppose you'll mostly do things with recursion. E.g fibonacci numbers would look like:

def fib(n):
    if n < 2: return n
    else: return fib(n - 1) + fib(n - 2)

This probably means that some kind of automatic memoization must be used, so that functions of this kind wouldn't end up with terrible algorithmic complexity.

Personally I wouldn't mind compiler-checked "pure" functions that 1) only allow locals to be used, 2) only allows other pure functions to be called, 3) if an argument is a pointer/reference, it must be const. However, a pure function is not supposed to have any side-effects, but isn't the creation of a local object a side-effect in itself?

Jonatan Hedborg
Member #4,886
July 2004
avatar

My biggest gripe with "pure functional languages" is the lack of loops and local variables. I can't for my life see how those would impair the "pureness" in any way. I can totally see why pure functional methods can be useful (though impossible to do anything useful with, on itself), but why cripple yourself? Simply wanting to emulate a mathematical function is not reason enough imo.

-------
Sweden: Free from the shackles of Democracy since 2008-06-18!

axilmar
Member #1,204
April 2001

Vanneto said:

I think he got pure functions wrong, as far as I understand as long as you don't modify the global state you are free to do anything you want in the function.

Simply put, a pure function is a function that returns exactly the same output for a constant input.sin,strlen are both pure functions yet I doubt they don't have local variables.

The definition of pureness is quite tricky, and I admit that when I first read it, my interpretation was similar to yours. Unfortunately, it is not correct. Pureness must exist in all levels, inside and outside of the function in order to be considered pure. In short, strlen is definitely not pure. I do not know about 'sin'.

bamccaig said:

What exactly can a function that can't assign to anything even do? If nothing in your function or the functions it can call can do any assignment then you're pretty much just making a wrapper that does nothing.

Haskell is 100% pure, but it is Turing complete. You can do anything with a pure function. Pure functions allow variable initializations.

Quote:

I like the idea of being able to have the compiler ensure that a particular function (or Hell, class) can't have any global state. That's what I think pure should do.

That's what pure is about. It can make whole functions and classes pure.

bamccaig said:

C# handles that in a better way, IMHO. Conditional expressions must be Boolean so the compiler will error most of the time (the exception would be for an actual Boolean assignment expression). If that's what you really wanted then you would need to say if((x = 5) != 0) or something like that. It can be a pain to get used to at first when checking for null references, but overall I think it's a good rule and a better compromise than disallowing assignments as expressions.

In the way you propose it, you can always write (if (x = 5) == true). My purpose is to enforce some good programming practices as well as help reasoning about the program...that's why assignments are in between statements and expressions. It's very easy to misidentify '=' for '=='.

Quote:

Can main accept arguments directly and can it return an exit status?

Main's formal signature is:

func main(args : array[string] = array[string]()) : int;

It's just a wrapper over C's main function.

Quote:

Is there going to be an interface that you can implement to make a user-defined type usable with foreach?

Yes. You can overload operator foreach.

So good luck! It sounds like a very ambitions project.

Thank you. It's really a time consuming project. I will be lucky if I reach the translator to C stage.

anonymous said:

However, a pure function is not supposed to have any side-effects, but isn't the creation of a local object a side-effect in itself?

It is not, because the local object is not accessible from the outside world.

My biggest gripe with "pure functional languages" is the lack of loops and local variables. I can't for my life see how those would impair the "pureness" in any way. I can totally see why pure functional methods can be useful (though impossible to do anything useful with, on itself), but why cripple yourself? Simply wanting to emulate a mathematical function is not reason enough imo.

That's my gripe as well. For me, Haskell is really difficult. I have a big problem writing complex Haskell applications. My mind is simply not powerful enough to combine all the individual solutions in one big loop, for example, in gui applications.

Jonatan Hedborg
Member #4,886
July 2004
avatar

axilmar said:

Haskell is 100% pure, but it is Turing complete. You can do anything with a pure function.

You cant read stuff from the keyboard/internet/random number generator.

That's why haskell isn't a 100% pure functional language - it has some language construct to say that a function is non-pure... Can't remember what it is at the moment.

-------
Sweden: Free from the shackles of Democracy since 2008-06-18!

axilmar
Member #1,204
April 2001

You cant read stuff from the keyboard/internet/random number generator.

Yes, you can, using PerformUnsafeIO.

Quote:

That's why haskell isn't a 100% pure functional language - it has some language construct to say that a function is non-pure... Can't remember what it is at the moment.

Ok, now I understand what you meant. Indeed, no language can be 100% pure in that sense.

I've started my informal specs with a discussion about modules.

Dustin Dettmer
Member #3,935
October 2003
avatar

Show us some example code :D

axilmar
Member #1,204
April 2001

Show us some example code

I've written a post in my blog with plenty of code samples.

Vanneto
Member #8,643
May 2007

func main()
{
    ...
}

Really? Is the tion really so hard to type? Can't it just be function?

In capitalist America bank robs you.

axilmar
Member #1,204
April 2001

Vanneto said:

Really? Is the tion really so hard to type? Can't it just be function?

Yes, it could be. But then, for consistency, I would have to expand all keywords: 'variable' instead of 'var', 'type_definition' instead of 'typedef', 'thread_specific' instead of 'threadspec', 'linkage_specification' instead of 'linkspec', 'constant' instead of 'const', 'enumeration' instead of 'enum' etc.

I actually wanted to be 'fun', but 'fun' is a specific English word, so it's not really suitable for this.

bamccaig
Member #7,536
July 2006
avatar

http://axilmarpl.blogspot.com/2010/01/specs-part-1-modules.html?showComment=1264690146368#c2095125692262182123

** EDIT **

Commenting on the blog seems too spammy.

This is very useful because it allows importing a whole bunch of modules with a single statement; for example, if one wanted to make a GUI application, he did not have to import every child module of the gui submodule; a simple statement like this:

import std.gui;

would be more than enough to import any necessary module for gui development.

Although you'll probably never need to import std.gui because you'll probably have imported std for something (maybe a printf equivalent) and that means everything in the std module (which I assume is the standard library) is already imported, perhaps gui, net, security, xml, etc., etc., etc.!

IMHO, with that model, you might as well not even have an import statement and just import everything in the import path automatically, compile-time be damned (perhaps you can use a cache with a special command to update it to improve performance). I suspect that's what you'll end up with much of the time anyway, but with meaningless import statements littering all of the source files.

As I said in the blog comments, I think it makes better sense to not implicitly import sub-modules.

:-/

See also: [1] [2] [3]

Edit: Unless I'm completely misunderstanding modules. I see them as namespaces, which when imported bring their declarations and definitions into the global namespace. If it only loads the modules into a module wrapper (such that you need to access everything through the module name) then I guess the only real harm is performance, which as I suggested, can be improved with a cache.

But there is a difference: in this language, the code inside the [class section] has access to the variables defined in the ... class!

...

Since a section is like a class, it can have its own return and assignment operators.

Now 'sections' are interesting. What was the inspiration for them?

And how does the 'return' operator work? It strikes me as being similar to default properties in *shudder* Visual Basic. At first I thought it was a cool feature, but ultimately decided it really wasn't. How do you differentiate between, for example, wanting to pass the object and wanting to pass the result of the return operator?

#SelectExpand
1class Foo 2{ 3 var x_ : int; 4public: 5 func constructor(int x) 6 { 7 this.x_ = x; 8 } 9 10 func operator return () : int 11 { 12 return this.x_; 13 } 14} 15 16func someFunction(x : int) 17{ 18 /* ...etc... */ 19} 20 21func someFunction(f : Foo) 22{ 23 /* ...etc ... */ 24} 25 26... 27 28var o : Foo(5); // I'm not sure about syntax. 29 30someFunction(o); // Which someFunction is called?

Dustin Dettmer
Member #3,935
October 2003
avatar

I skimmed the blog post but the example code was sparse. In reality I don't have time to study your (potentially) cool new language :P.

If you had an example program (100 lines or so) I could grasp a good deal of your language quickly (which is all I have time for).

axilmar
Member #1,204
April 2001

bamccaig,

I don't think that there is going to be a problem with the module system. If the modules are organized hierarchically and in a proper manner, then the programmer will have the options of importing either single modules (i.e. modules without children) or a parent module that includes everything else.

The standard library, if there is one, will not be named std, but something along pl.system.collections, pl.system.types, pl.system.gc etc, allowing you to import whatever you want at the level you want it.

bamccaig said:

Now 'sections' are interesting. What was the inspiration for them?

Writing properties in c++.

Quote:

And how does the 'return' operator work? It strikes me as being similar to default properties in shudder Visual Basic. At first I thought it was a cool feature, but ultimately decided it really wasn't. How do you differentiate between, for example, wanting to pass the object and wanting to pass the result of the return operator?

The return operator is the same as the 'operator type' in c++: when an evaluation of a value to that type is requested, the return operator is invoked. I did not do it like c++ for syntax consistency reasons. You can think of the return operator as a conversion to a specific type.

Quote:

var o : Foo(5); // I'm not sure about syntax.

It's

var o = Foo(5);

Quote:

someFunction(o); // Which someFunction is called?

The function 'someFunction(Foo)' is called.

If you had an example program (100 lines or so)

What would you like to see?

van_houtte
Member #11,605
January 2010
avatar

fyi this thread was created on monday by somebody who runs gentoo, take this as you will.
;D

-----
For assistance, please register and click on this link to PM a moderator

Sometimes you may have to send 3-4 messages

bamccaig
Member #7,536
July 2006
avatar

axilmar said:

If the modules are organized hierarchically and in a proper manner, then the programmer will have the options of importing either single modules (i.e. modules without children) or a parent module that includes everything else.

OK, now I understand better. It's almost akin to creating a main header file for a library that includes all of the other header files. In other words, top-level modules should only contain the bare essential code that doesn't fit elsewhere, but as much as possible should be neatly organized into sub-modules?

Vanneto
Member #8,643
May 2007

Includes and imports are overrated. Why not just let the compiler decide from the code written what it should import? We have powerfull CPUs and lots of memory. All those header files. Yeesh.

Get on with the time. ;)

In capitalist America bank robs you.

axilmar
Member #1,204
April 2001

bamccaig said:

OK, now I understand better. It's almost akin to creating a main header file for a library that includes all of the other header files. In other words, top-level modules should only contain the bare essential code that doesn't fit elsewhere, but as much as possible should be neatly organized into sub-modules?

Yeap.

...

After much thinking, and thanks to this discussion, I decided to enable 3 crucial unsafe operations in my language. The operations are enabled only when they are marked 'unsafe', which will be turned off by a compiler switch.

The 3 operations are:

1. pointer arithmetic.
2. pointers in unions.
3. casts.

Here is how to use them in the code:

#SelectExpand
1//unsafe ptr declaration 2var p : unsafe *int; 3 4//pointer arithmetic using unsafe pointers; 5//normally this is not allowed. 6p++; 7 8//pointers in unions 9typedef ALLEGRO_DISPLAY_EVENT : unsafe union { 10 id : ALLEGRO_EVENT_ID, 11 source : *ALLEGRO_DISPLAY, 12 ... 13}; 14typedef ALLEGRO_EVENT : unsafe union { 15 ALLEGRO_DISPLAY_EVENT, 16 ALLEGRO_JOYSTICK_EVENT, 17 .... 18}; 19 20//unsafe casts 21var i = unsafe(int)p;

I decided to add these unsafe operations for the following reasons:

1) in order to eliminate much boilerplate code that would be required otherwise. This allows Allegro5 to be directly written in this language, without writing anything in C.

2) enable the programmer to directly use external C functions that require these operations. For example, using malloc to allocate memory for a class and then casting the result to the appropriate type.

EDIT:

I uploaded a sample source code file that contains the struct and union declarations for Allegro5 events. The file is parsed using the grammar without error.

SiegeLord
Member #7,827
October 2006
avatar

What sort of compile time introspection will you support? In D I can have a struct, and using its introspection abilities can generate a manager class that can do stuff to the structs variables (using the variables' types and names to determine what exactly needs to be done), check to see what function are defined in it etc etc. This is definitely a critical feature for me.

Or perhaps this is for the future features? AxPL 2 perhaps?

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Dustin Dettmer
Member #3,935
October 2003
avatar

axilmar said:

What would you like to see?

How about Tetris or Pong?

Jeff Bernard
Member #6,698
December 2005
avatar

axilmar said:

What would you like to see?

How about Tetris or Pong?

An MMORPG that can be used as a code example for every type of game. You should prolly team up with piccolo and port The Game.

--
I thought I was wrong once, but I was mistaken.

Matthew Leverton
Supreme Loser
January 1999
avatar

SiegeLord said:

In D I can have a struct, and using its introspection abilities can generate a manager class that can do stuff to the structs variables (using the variables' types and names to determine what exactly needs to be done), check to see what function are defined in it etc etc.

Can you provide a link that shows source code examples of this?

Oscar Giner
Member #2,207
April 2002
avatar

Vanneto said:

Includes and imports are overrated. Why not just let the compiler decide from the code written what it should import? We have powerfull CPUs and lots of memory. All those header files. Yeesh.

There are already languages that do it. Eiffel for example. It automatically compiles all classes that your program uses.

About Pure funcions, it's something similar to Referential transparency? It looks like Pure functions have more constraints though.

SiegeLord
Member #7,827
October 2006
avatar

Can you provide a link that shows source code examples of this?

No, but here's a quick example I whipped up right now. It's inane, and you'd probably want to make the manager classes implement some sort of interface, so that you don't actually need to know their names.

#SelectExpand
1import tango.io.Stdout; 2import struct_wrapper; 3 4struct StructA 5{ 6 int x = 0; 7 int y = 0; 8 double z = 0; 9} 10 11struct StructB 12{ 13 int x = 0; 14 15 void Negate() 16 { 17 x = -x; 18 } 19} 20 21mixin(WrapStruct!("StructA")); //Creates a class called StructAManager 22mixin(WrapStruct!("StructB")); //Creates a class called StructBManager 23 24void main() 25{ 26 StructA a; 27 StructB b; 28 29 auto a_manager = new StructAManager(); 30 auto b_manager = new StructBManager(); 31 32 a_manager.IncrementDoubles(a); 33 a_manager.IncrementIntegers(a); 34 a_manager.Negate(a); 35 36 Stdout.formatln("{} {} {}", a.x, a.y, a.z); // 1 1 1.00 37 38 b_manager.IncrementDoubles(b); 39 b_manager.IncrementIntegers(b); 40 b_manager.Negate(b); 41 42 Stdout.formatln("{}", b.x); // -1 43}

#SelectExpand
1module struct_wrapper; 2 3public import utils; 4 5/* 6 * WrapStruct is required to instantiate the WrapStruct2 mixin at the scope 7 * of the struct that we are wrapping 8 */ 9char[] WrapStruct(char[] struct_name)() 10{ 11 return 12`mixin WrapStruct2!("` ~ struct_name ~ `")` ~ struct_name ~ `dummy; 13mixin(`~ struct_name ~ `dummy.Gen()); 14`; 15} 16 17template WrapStruct2(char[] struct_name) 18{ 19 char[] Gen() 20 { 21 char[] ret; 22 23 auto names = GetNamesInAlias!(mixin(struct_name))(); 24 auto types = GetTypesInAlias!(mixin(struct_name))(); 25 const n = mixin(struct_name).tupleof.length; 26 27 char[][] integers; 28 char[][] doubles; 29 30 for(int ii = 0; ii < n; ii++) 31 { 32 switch(types[ii]) 33 { 34 case "int": 35 integers ~= names[ii]; 36 break; 37 case "double": 38 doubles ~= names[ii]; 39 break; 40 default: 41 } 42 } 43 44 ret ~= 45`class ` ~ struct_name ~ `Manager 46{ 47 void IncrementIntegers(ref ` ~ struct_name ~ ` strct) 48 { 49`; 50 foreach(val; integers) 51 { 52 ret ~= 53` strct.` ~ val ~ ` += 1; 54`; 55 } 56 ret ~= 57` } 58 59 void IncrementDoubles(ref ` ~ struct_name ~ ` strct) 60 { 61`; 62 foreach(val; doubles) 63 { 64 ret ~= `strct.` ~ val ~ ` += 1.0; 65`; 66 } 67 ret ~= 68` } 69 70 void Negate(ref ` ~ struct_name ~ ` strct) 71 { 72`; 73 if(mixin(`is(typeof(` ~ struct_name ~ `.Negate))`)) 74 { 75 ret ~= 76` strct.Negate(); 77`; 78 } 79 ret ~= 80` } 81}`; 82 return ret; 83 } 84}

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

axilmar
Member #1,204
April 2001

SiegeLord said:

What sort of compile time introspection will you support?

Introspection is planned from day 1. You will be able to create instances, call their methods, get and set their members through introspection. Introspection will work both at class level and at module level.

Quote:

How about Tetris or Pong?

I'll try a Pong game, which seems easier than Tetris.

About Pure funcions, it's something similar to Referential transparency [en.wikipedia.org]? It looks like Pure functions have more constraints though.

Pure functions is exactly the same as referential transparency.

EDIT:

I attached a Pong game; I don't know if it would run, but it checks out ok in the gold parser.

Thomas Fjellstrom
Member #476
June 2000
avatar

You realize that .pl has been used by perl scripts since day one right? (20+ years)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730



Go to: