The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

what do you think of this syntax?

I'm making a new language for fun and to fill time when I get deployed in 5 weeks.  I want to regularize syntax (though not going as far as lisp), while still making my language easy to pick up.  Most of my design is really elegant, but I'm kind of worried about how functions will look.

My language:

int(int) f(i)
{
    return i*2;
};

C++ version:

int f(int i)
{
    return i*2;
}

My syntax turns all declarations into:

type identifier { value };

See in C++ you have:

int i(4); //initialize int i with 4
int ia[3] = {100,200,300}; //initialize int array with values

in my language you would have:

int i{4};
int[3]{100,200,300};

See more regular?  However then the functions start to look funny.  It does give you more power.  The : is the symbol for reference so if you see this "int(int):" you have a reference to a function that returns an int given an int.  I might actually change it to (int)(int).  Essentially functions transform tuples (plus provide side effects).
Tom
Saturday, October 22, 2005
 
 
left out an identifier, that line should be:
int[3] ia {100,200,300};
Tom
Saturday, October 22, 2005
 
 
So a function with two parameters would be:

int(int, int) f(i, j)
{
    return i*j;
};

I must say for variable declarations it's a much cleaner syntax.  However, I really don't like the separation of types from parameters.  When I edit a function definition, I consider the type and parameter together -- this design forces me to keep them separate. 

I think you should offer an exception in this case, allowing people to declare functions this way and the usual C++ style.  I think your style has some advantages when it comes to callbacks and typedefs:

int_callback f(i, i) { ...

With int_callback defined as int(int, int).  I'd even go so far as to offer both syntaxes simultaneously:

// This was cause a syntax error since float j
// doesn't match int_callback definition.
int_callback f(int i, float j);

I really really hate (int)(int, int) syntax-- I've used that for callback typedefs in C++ and it always makes my head spin.  I'm not 100% sure that int(int, int) is the best syntax either but it's better than the alternative.
Almost H. Anonymous Send private email
Saturday, October 22, 2005
 
 
Thanks for the feedback!

Ok for starters, how is this?

int(int i, int j) f
{
    return i*j;
};

kind of weird, as i and j are not part of the type.  Then again i and j are not part of the identifier.  Instead they are part of the scope/namespace of f.  This might work:

int(int i, int j) f
{
    return i*j;
}


However what if I want to return two values?

(int min,int max):(int left, int right) order
{
    if(left<right)
        min,max=left,right;
    else
        min,max=right,left;
};

the type would be (int,int)(int,int), or (int,int):(int,int), if I grab the : for this purpose and give the @ to pointers and the & to references.  A little symbol swapping won't hurt too much, at least not at this stage.

How does the function look?  Is a function's ugliness the sum of the ugliness of each line or is it weighted to the ugliest line?

I've been thinking about templates, function overloading, and virtual parameters.  I want virtual parameters, other than the this pointer.  Something like this, using C++ style syntax:

void HandleCollision(virtual Entity& left, virtual Entity& right)=0;

void HandleCollision(Car& left, Car& right)
{
  //blah blah blah
}

void HandleCollision(Person& left, Person& right)
{
  //blah blah blah
}


void HandleCollision(Person& left, Car& right)
{
  //blah blah blah
}

void HandleCollision(Car& left, Person& right)
{
  HandleCollision(right,left);
}

vector<Entity*> AllEntities;

for blah blah blah if close enough
    HandleCollision(*iter1,*iter2);

I have heard this called double dispatch before.  It cuts down on the case statements.  However C++ doesn't have it but programs like video games often need it.

I like templates so I want to keep all of that functionality.

In some ways specialization of templates is like implementing derived functions.  The difference is compile-time vs run-time.  Overloaded function names fit in there somewhere but not really.  Overloaded function names make life easier but there is no analog in either type names or instance names for variables.  Have to think more I guess.  I want to abstract it all out.
Tom
Saturday, October 22, 2005
 
 
How do you work the return type declaration into your pattern?
son of parnas
Saturday, October 22, 2005
 
 
the type of a function has two parts, the return type(s) and the parameter types.  Here is a sample function

(int min,int max)@(int left, int right) order
{
    if(left<right)
        min,max=left,right;
    else
        min,max=right,left;
};

Its type is (int,int)@(int,int).  You would read that as function that takes a pair of ints and returns a pair of ints.  The stuff before the @ would be the return type(s) and the stuff after would be the parameter types, and the whole line would be the function type.  Here is some code using the function:

int i{5};
int j{4};
int x;
int y;
x,y=order(i,j);//assigns j to x, and i to y

Here is a swap function

()@(int: left, int: right) swap
{
    left,right=right,left;
}

The empty parenthesis before the @ are equivilent to saying that the function returns void.

Gah, it seems that I am just throwing symbols around.  Not sure what to do.  Perhaps I should settle on one way or the other.

Ok I have three symbols and two, maybe three purposes for them.

I need one symbol to declare pointers and to get the address of an expression.

I need another symbol to declare references and to dereference pointers.

I probably need a symbol to declare functions.
Tom
Saturday, October 22, 2005
 
 
Given type identifier { value }, wouldn't a function be more like:


(int min,int max) order
{
  (int left, int right) ()
  {
      if(left<right)
          min,max=left,right;
      else
          min,max=right,left;
  }
}
son of parnas
Saturday, October 22, 2005
 
 
I don't understand your example, could you explain it?  The nesting doesn't make sense to me, and it seems like this could be used interchangeably with an int,int tuple.  I do not remember if I mentioned it but I intend for this language to have strict compile-time type checking.
Tom
Saturday, October 22, 2005
 
 
So your language is C++ but with different syntax?  What's the point?  Give me something new and I might be interested.
Jonas Quimby Send private email
Saturday, October 22, 2005
 
 
1) no, it is more like a C++/lisp hybrid.  I want to generalize language constructs while keeping as much as possible compile-time so that the compiler can find errors for you.  I am on the verge of deciding that there will be no class/struct keyword, and that instead of class definitions I'll just typedef the results of functions to be default constructors.  However that is unituitive so I'm trying to avoid jumping off that cliff.

2) I don't expect you to use it.  I'm going to have a few hours of free time per day in Iraq and not much to do.  I need a long block of time to do any real programming (at least a weekend) but I will not have a single day off over their.  So this should keep me busy.  If I come home with something cool that I can put on a resume so much the better.
Tom
Saturday, October 22, 2005
 
 
"1) no, it is more like a C++/lisp hybrid.  I want to generalize language constructs while keeping as much as possible compile-time so that the compiler can find errors for you.  I am on the verge of deciding that there will be no class/struct keyword, and that instead of class definitions I'll just typedef the results of functions to be default constructors.  However that is unituitive so I'm trying to avoid jumping off that cliff."

Sounds a little like type classes in haskell.

Sunday, October 23, 2005
 
 
Personally I'm very fond of the Pascal syntax.  I believe it's easier to write a LL(1) parser for it, too, and I find LL(1) parsers allow much more meaningful error messages than your typical LR(1) parser.

Although, I find nothing wrong with the function declaration:

MyFunc(int i, int j) : int
  {
  }
or
int MyFunc(int i, int j)
  {
  }
The Pascal/VB declaration, where a subroutine which returns a value is called a 'function', and a subroutine which does NOT return a value is called a 'Sub' or "Procedure", is a little odd at first, but less ambiguous than the C 'void' return type.

And I do like the Perl approach of declaring every function a 'sub', whether it returns a value or not.  Ambiguous, yes, but you can fix that in the comments.
AllanL5
Monday, October 24, 2005
 
 
There are plenty of languages out there, what you really want to do is enhance an existing language. Improve a process and design a framework to leverage a technology.

What is your language going to do that the millions of other C++ wannabes don't already do?

Consider C Sharp .NET 2.0 -> 3.0. The language is under-going some changes that will mean developers will be free to attempt problems in new ways. Adding functional constructs to a procedural language hasn't really been done before, and I believe this will be a success as it combines the best of both parrallels.

If you want people to pick up your language easily the yntax should be C/Java like.
At the end of the day, those languages already have frameworks etc available so which would you use?
Kierenski Send private email
Friday, November 04, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz