Advertisement

Scripting Language Genesis

Started by November 01, 2004 07:28 AM
116 comments, last by cmp 20 years, 2 months ago
The syntax of this language is just getting more and more complex.

I mean, just look at this:

Quote:

Why bring 'system' into this. Noting that 'if' only makes sense when applied to something of boolean type, I conclude that 'if' should be encapsulated with the boolean type.
(x<7).if
x = 7

Or, we can say that a boolean is a function that calls its argument.
x < 7
x = 7

Then we'd define the special function boolean.call as
boolean.call(true, function f) = f
boolean.call(false, function f) = false


Are you joking me? I might as well program in BrainF**k. Honestly, lets have some common sense here. (x<7).if is completely nonsensical. Once you start writing things like that, the language no longer makes sense.

If I have to pick on key thing about a language, it should be that you can read what it says outloud and it will make sense. I should be able to read "Integer X equals 7. If X does equal 7, printf 'Hello Wolrd!' Else, printf 'Woah, what went wrong?'"

Try taking your syntax and making a sentence. It doesn't make sense. That very fact should make you rethink how you want to do this. Perhaps I am thinking too procedurally...but quite honestly your syntax is getting less and less intuitive as you try to make it feature rich and strictly object oriented. Perhaps I can understand static classes as means for primitive manipulation...MAYBE. But still...how the hell does this make sense? "X is less than seven...if..."

I want to see a design document baby!
Quote:
Original post by C-Junkie
Quote:
Original post by umbrae
They are a cut down closure - I'm not sure if I want to handle funcitons referencing variables that don't exist any more, sounds like a can of worms to me.
Indeed. The language 'D' does half-hearted closures like this. It requires that the scope still exist so it doesn't have to deal with that "can of worms."

Do you think implementing full closures is worth it? I was thinking that these closure type things are really good, and with function pointers will make a suitable replacement for full closures.

Are full closures worth it? Other languages get along fine without closures at all, if I provide these half closures is it going to be good?

Quote:
Original post by Mayrel
Hmm. They work best when mixed with a number of other features. The programming language Icon does this particularly elegantly.

(code)

The type of closure that I was thinking about implementing will be able to do this also
actor[] a = actor.map    return value.name == "foo"

a will now contain all the actors with the name "foo"
Quote:
No. But I would like a language that had 'boolean closure type things' in the 'core of the language', and 'if' syntax provided in terms of that.

My thinking exactly, and it would make programming the virtual machine easier if everything was just method calls with function pointers.

Quote:
Original post by visage
Are you joking me? I might as well program in BrainF**k. Honestly, lets have some common sense here. (x<7).if is completely nonsensical. Once you start writing things like that, the language no longer makes sense.

Agree with you 100% :P
But if the underlyings of the language worked what way, if the compiler translated the if statement into a "my type of closure" call on a boolean - the insides of the language would be awesome.

Quote:
I want to see a design document baby!

If I can get the language stable, then I will do just that. As you can see, it really is in a state of flux at the moment.

[Edited by - umbrae on November 16, 2004 1:19:05 AM]
Advertisement
Quote:
Original post by umbrae
Are full closures worth it? Other languages get along fine without closures at all, if I provide these half closures is it going to be good?
Yes. Halfhearted closures are good enough to do everything you seem to want closures to be able to do. (work in if,each,for,while, etc etc etc)
Quote:
Original post by C-Junkie
Quote:
Original post by umbrae
Are full closures worth it? Other languages get along fine without closures at all, if I provide these half closures is it going to be good?
Yes. Halfhearted closures are good enough to do everything you seem to want closures to be able to do. (work in if,each,for,while, etc etc etc)

That was what I was thinking as well.

I need some sort of syntax to be able to define closure acceptors in classes. Because there are two methods involved, the method itself, and the closure that it calls - it is a little tricky. These are a few examples that I came up with
- list each(){object closure(object o)}- list each(){object(object o)}- list {object each(object o)}- list object each{object o}


I like the second one, it implies that the method each each accepts a closure that returns an object and takes as a parameter another object. Perhaps that can also be a type, eg.

object(object o) m = base.method


The variable m now is a pointer to the function base.method, and can be invoked as such. eg object fred = m.call(bob).

But maybe that is taking things too far. Having method types?

An if method using the second syntax
void if(boolean b){void()}

The method takes a boolean, and the closure that it calls has no parameters and returns nothing.

[Edited by - umbrae on November 16, 2004 1:11:34 AM]
from what i have understood closures are quite the same as lamda functions with access to variables of an extern scope.
Quote:

I need some sort of syntax to be able to define closure acceptors in classes. Because there are two methods involved, the method itself, and the closure that it calls - it is a little tricky. These are a few examples that I came up with


as you have an indent based language this wont work, but in my langauge i would use sth. like this:
class list<T>{   void for_each(procedure<tuple<T>> func){       iterator iter = begin       while(iter != end){            func(iter.item)       }   }   list<T> map(function<bool, tuple<T>> func){       list<T> result       for_each(lamda{ if(func(?1) == true) result.append(?1) })       return result   }}

so you would actually define a class function and a class procedure, one returning a value one doing it not.
now your colsure syntax would return an instance of a superclass of function/predicate (depending on the existance of a return).
now you could call it this way:
[0,1,2,3,4,5,6,7,8,9,10].map( lambda{ return (?1 % 2) == 0 } )
wich would return [0,2,4,6,8,10]

a problem of your syntax is btw. that a function cannot accept multiple closures.

[Edited by - cmp on November 16, 2004 2:16:48 PM]
Quote:
Original post by cmp
from what i have understood closures are quite the same as lamda functions with access to variables of an extern scope.

Seems like it.

Quote:
as you have an indent based language this wont work, but in my langauge i would use sth. like this:
*** Source Snippet Removed ***

It's been used a lot, but what exactly is sth? It sounds like stuff, and starts off like standard template library, but doesn't quite get there. I'm not sure what you mean :S.

I'm also not sure that because voodoo is a indent based language that your code won't work, wouldn't this do the same:
class list<T>   void for_each(procedure<tuple<T>> func)       iterator iter = begin       while(iter != end)            func(iter.item)   list<T> map(function<bool, tuple<T>> func)       list<T> result       for_each(lamda           if(func(?1) == true) result.append(?1)       )       return result


Quote:
so you would actually define a class function and a class procedure, one returning a value one doing it not.

Maybe both subclassing from the same class "method".

Quote:
a problem of your syntax is btw. that a function cannot accept multiple closures.

When you say multiple closures I guess you mean at the same time, eg two closures for one function. I suppose you could have this syntax to do two closures:
class list    list each(){void(object o) m1, object() m2}

Just having a comma between definitions. I'm not sure how the syntax for defining closures would look though, because of the tab blocks you can't find the gap between each method. Maybe a return breaks between each method. Even if the method returns void, you still need a return there to signify the end of the method.

But then again, do we need multiple closure functions? It would be cool I agree, but in practical terms would it be used often?
Advertisement
Quote:
Original post by umbrae
I need some sort of syntax to be able to define closure acceptors in classes. Because there are two methods involved, the method itself, and the closure that it calls - it is a little tricky. These are a few examples that I came up with
- list each(){object closure(object o)}- list each(){object(object o)}- list {object each(object o)}- list object each{object o}

I like the second one, it implies that the method each each accepts a closure that returns an object and takes as a parameter another object.

I don't think that the second one implies any such thing. Note that you use indentation to indicate code blocks, not brace characters. So why would a user of your language associate a brace with a block?

I don't see why you couldn't have list each (void(T& o) f). You do as I suggested and have a block after a call be magically turned into a function, and it's still obvious that you could pass a function name to it:
inc (T& o)  o++;list<int> l = [ 1, 2, 3, 4 ]// You could do:l.each(inc)// Or:l.each  lambda(int& i)    ++i

Quote:

But maybe that is taking things too far. Having method types?

I don't see why. In a static language, where 'methods' are primarily a compile-time concept, it is extra work to have method types. But scripting languages are typically dynamic: method objects will exist at runtime, so making them visible to the script-writer should not be overly troublesome.
Quote:
Original post by cmp
as you have an indent based language this wont work, but in my langauge i would use sth. like this:

Looks like your 'map' is actually a filter.

ML/Haskell-like
type List T = EmptyList | Pair(T, List(T));definition.[] = List();[ x, ... ] = List(x, [...]);x :: xl = List(x, xl);for_each []      func = ();for_each x :: xl func = func(x), for_each(xl, func);filter []      pred = []filter x :: xl pred = if pred(x) then x :: filter(xl, pred)                                 else filter(xl, pred);filter [ 0, 1, 2, 3, 4, 5, 6, 6, 7, 9, 10] { 0 == ?1 % 2 };

Lisp-like (note lists are always already defined in any Lisp).
(define (for-each l f)  (match l (()       ())           ((x . xl) (f x) (for-each xl f))))(define (filter l pred)  (define result ())  (for-each l [if (pred _) (append result _)])  result)(filter (0 1 2 3 4 5 6 7 9 10) [even _])
CoV
Quote:
Original post by Mayrel
I don't think that the second one implies any such thing. Note that you use indentation to indicate code blocks, not brace characters. So why would a user of your language associate a brace with a block?

I don't see why you couldn't have list each (void(T& o) f). You do as I suggested and have a block after a call be magically turned into a function, and it's still obvious that you could pass a function name to it:

You use the term "magically", and to me that is a bad thing. Closures aren't the same as parameters, and having parameters "magically" turn into closures seems bad in my book.

I think that it is better to have a different, if unusual syntax than mix closures with parameters.

This could also work
- list each()(object(object o))


Quote:
Quote:
But maybe that is taking things too far. Having method types?

I don't see why. In a static language, where 'methods' are primarily a compile-time concept, it is extra work to have method types. But scripting languages are typically dynamic: method objects will exist at runtime, so making them visible to the script-writer should not be overly troublesome.

I wasn't talking about the difficulty in implementing it, just if they are needed and would make a good addition to a scripting language.

Quote:
Looks like your 'map' is actually a filter.

I was thinking that as well, I've used Haskell a bit and found it quite cool.
Quote:
Original post by umbrae
Quote:
Original post by Mayrel
I don't think that the second one implies any such thing. Note that you use indentation to indicate code blocks, not brace characters. So why would a user of your language associate a brace with a block?

I don't see why you couldn't have list each (void(T& o) f). You do as I suggested and have a block after a call be magically turned into a function, and it's still obvious that you could pass a function name to it:

You use the term "magically", and to me that is a bad thing. Closures aren't the same as parameters, and having parameters "magically" turn into closures seems bad in my book.

Well, no. Closures are a kind of object, whilst a parameter is a kind of variable. So clearly they aren't the same. But integers are objects and they can be passed in a parameter. So there's no reason you shouldn't do the same to closures.

I will note that every language that I am aware of that uses closures treats them as just another object.
Quote:

Quote:
Quote:
But maybe that is taking things too far. Having method types?

I don't see why. In a static language, where 'methods' are primarily a compile-time concept, it is extra work to have method types. But scripting languages are typically dynamic: method objects will exist at runtime, so making them visible to the script-writer should not be overly troublesome.

I wasn't talking about the difficulty in implementing it, just if they are needed and would make a good addition to a scripting language.

If a feature is almost free, doesn't use up syntax that would be better used for something else, and isn't actively dangerous, you should put it in. In those kinds of cases, wondering whether or not people will want to use them is silly.

People who don't want to use them won't, and people who do want to use them will. If it turned out that nobody used them, which I very much doubt would be the case, you've hardly wasted any work, since all you've had to do is expose the method type that must already exist inside the engine.
CoV
Quote:
Original post by Mayrel
Well, no. Closures are a kind of object, whilst a parameter is a kind of variable. So clearly they aren't the same. But integers are objects and they can be passed in a parameter. So there's no reason you shouldn't do the same to closures.

I will note that every language that I am aware of that uses closures treats them as just another object.

My bad, I was referring to the half-hearted closures that I was planning to implement - they aren't objects.

Quote:
If a feature is almost free, doesn't use up syntax that would be better used for something else, and isn't actively dangerous, you should put it in. In those kinds of cases, wondering whether or not people will want to use them is silly.

People who don't want to use them won't, and people who do want to use them will. If it turned out that nobody used them, which I very much doubt would be the case, you've hardly wasted any work, since all you've had to do is expose the method type that must already exist inside the engine.

I agree with you on some level, but what I don't want in a language is a cacophony of features. When I was reading about scheme I really liked it's philosophy. It's very minimalistic and doesn't add features even if they might be a bit useful. As I remember php started out as a very fast, small scripting language. But it has now grown, and uses up more resources. A lot of languages start small, but then they start to gather more features, and before you know it - they are java. :P But seriously, I think a small subset of features is good, with more functionality built on top of that.

That said, I think method variables are very good - and I will have a go at putting them in the language.

The point in question is whether to allow closures as a parameter for a method.
class list    // a normal function    void each(void(object value) m)// calling code, this is okaylist a = [1,2,3]a.each(an_object.a_method)// is this okay? (closures a replacement for a method?)a.each    system.println(value)


I'm in two minds about this, I think it is good, and makes sense - but I also think there needs to be a difference in syntax when defining closures. You could define both, and let overloading take it's course
class list    // this takes a function    void each(void(object value))    // this takes a closure    void each()(void(object value) m)

I think that there is too much ambiguity when defining closure accepting methods just by having the function definitions as the closure. Because this language is currently lined up to be a tabbed block language, it makes it harder because I think that something like this doesn't look right:
class base    // a closure accepting method    void method(integer i, object() m, boolean b)// calling that methodbase bb.method(4,    if (i > 7)        return new integer    else        return new decimal    , true)


How to indent it is not well defined, and it is hard to see what is happening. You could make a rule that method parameters always have to be at the back, but then you still need the ending ")". It is for this reason that I think that closure accepting methods need to have a different syntax, and I am considering only allowing one closure per method.

[Edited by - umbrae on November 17, 2004 9:15:15 PM]

This topic is closed to new replies.

Advertisement