www.digitalmars.com         C & C++   DMDScript  

D - First-class Functions

reply Mark Evans <Mark_member pathlink.com> writes:
Think beyond "anonymous functions" -- go all the way and make functions
first-class.  Then you have real power at your fingertips, a true functional
language.  -M.

http://puma.wellesley.edu/~cs251/spring02/first-class-functions.pdf
Feb 19 2003
parent reply Mark Evans <Mark_member pathlink.com> writes:
That Wellesley CS professor's summary of first-class functions is not entirely
correct.  (He skirts some issues for the sake of not confusing students.)

Microsoft's Vault site has a better discussion.  It warns, "The distinction
between a Vault function and a C function pointer can be rather subtle."  The
concept of closure is what counts here.

http://research.microsoft.com/vault/learn/tutorial/closures.htm

It is vindication for my point of view that Microsoft should adopt first-class
functions in its version of "the next systems language" and I hope D does the
same.

Mark

Think beyond "anonymous functions" -- go all the way and make functions
first-class.  Then you have real power at your fingertips, a true functional
language.  -M.
http://puma.wellesley.edu/~cs251/spring02/first-class-functions.pdf

Feb 19 2003
next sibling parent reply Mark Evans <Mark_member pathlink.com> writes:
Frequently Asked Questions for comp.lang.functional:
http://www.cs.nott.ac.uk/~gmh//faq.html
Feb 19 2003
parent reply Mark Evans <Mark_member pathlink.com> writes:
Dan keeps talking about delegates.  This talk is dangerous.

Proper language design "compiles out" many legacy design patterns, and I
recently posted links on that subject.  The pattern disappears when the language
removes all need for it.  So describing a language in terms of the patterns it
replaces is convoluted and confusing; it describes with something that no longer
exists.  Instead, describe the language in terms of the features that do exist,
and that replaced the patterns.  Terms like "closure" and "first-class function"
are very standard.

Walter's remark about difficulty of implementation is worrisome.  D is a new
language, and first-class functions should not be overly difficult, though they
entail a good refactoring and redesign.  The kind of evolutionary dead-end
suggested by Walter's remarks is exactly why I keep harping on the dangers of
using C++ exclusively as a design foundation. It's critically important to think
more generally than that; widen the gene pool with other languages.  You all
know what happens when the gene pool is too small -- defects and extinction!

Mark
Feb 20 2003
parent reply Bill Cox <bill viasic.com> writes:
Hi, Mark.

BTW, I've really enjoyed following all the links you've posted.  Very 
educational.  Keep it up!

I cut my baby programmer teeth on Lisp, which has first class functions. 
  Some people look at my code and say Lisp ruined me (too many small 
functions).  I also write a LOT of C, and some C++.

In all the C code I've written, I haven't missed Lisp's first class 
functions.  Not once.  I think they are an anceint concept (40 or 50 
years now?) that may be evolving out of the gene pool.

I'm much more interested in some of the newer features being included in 
some of the languages you've dug up.  D already includes many of them. 
Two of the ones I believe I would actually use are:

- Powerful iterators.  I hate writing recursive iterators and passing 
callback functions to them.  Newer schemes like Sather's eliminate that.
- Modifying existing classes directly.  Nice does this, allowing 
additional methods.  Sather does this even better, allowing class code 
to be directly incorporated into a new class with arbitrary 
modifications.  That really rocks.  I'd use that all the time.

Bill Cox

Mark Evans wrote:
 Dan keeps talking about delegates.  This talk is dangerous.
 
 Proper language design "compiles out" many legacy design patterns, and I
 recently posted links on that subject.  The pattern disappears when the
language
 removes all need for it.  So describing a language in terms of the patterns it
 replaces is convoluted and confusing; it describes with something that no
longer
 exists.  Instead, describe the language in terms of the features that do exist,
 and that replaced the patterns.  Terms like "closure" and "first-class
function"
 are very standard.
 
 Walter's remark about difficulty of implementation is worrisome.  D is a new
 language, and first-class functions should not be overly difficult, though they
 entail a good refactoring and redesign.  The kind of evolutionary dead-end
 suggested by Walter's remarks is exactly why I keep harping on the dangers of
 using C++ exclusively as a design foundation. It's critically important to
think
 more generally than that; widen the gene pool with other languages.  You all
 know what happens when the gene pool is too small -- defects and extinction!
 
 Mark
 
 

Feb 21 2003
parent reply Mark Evans <Mark_member pathlink.com> writes:
I cut my baby programmer teeth on Lisp.... 
I also write a LOT of C, and some C++.
In all the C code I've written, I haven't missed Lisp's first class 
functions.  Not once.

Well McCarthy, the creator of Lisp, got some things wrong. http://www.cs.brown.edu/courses/cs173/2001/Lectures/2001-09-21.pdf It's also possible that you were never a good Lisp programmer. I know plenty of imperative (C, Pascal, FORTRAN) programmers who write code in functional languages which reads just like their favorite native tongue. The expressiveness of a functional language is wasted on them. I write "a LOT" of C and C++ too, but use other languages regularly, and often move between imperative and functional paradigms even within the same project. The difference in expressive power is quite staggering. As a rule I would always prefer to write something in a higher level style as would any intelligent programmer. It's just easier. I refer you back to my colleague's remarks about OCaml, which offers first-class functions. The computer science Ph.D.'s at Microsoft Research have incorporated first-class functions into Vault pursuing goals practically identical to D's. They are right on the money.
I think they are an anceint concept (40 or 50 
years now?) that may be evolving out of the gene pool.

That's like saying the wheel is going out of style. Here is a very interesting productivity contest between Lisp, Java, and C++. http://www.norvig.com/java-lisp.html "His results show that the resulting Lisp programs ran faster on average than C, C++ or Java programs (although the fastest Lisp program was not as fast as the fastest C program), and that Lisp programs took less development time than the other languages." Walter wrote:
 One point is the article saying that nested functions 'capture' the
 value of variables in the enclosing environment at the point of
 declaration of the nested function.

That 'environment capture' is called a closure. 'Nested functions' are not the key idea, so worrying about stack frames is off the mark. The nesting just arose because they wanted to show how FCF's permit precise scope control, i.e. no one but its caller needs visibility on that function. The Needle language offers not only first-class functions, but first-class continuations too. Icon has the same idea, though I'm not sure it's truly first-class. It's been a while since I wrote Icon code. Continuations are probably over the top for D, but I can envision them helping with interrupt service routines and multithreading. A better starting point on multithreading would be the Oz book which puts the entire subject in context. http://www.nongnu.org/needle/ http://www.info.ucl.ac.be/people/PVR/book.html Mark
Feb 21 2003
next sibling parent bill viasic.com writes:
In article <b3665m$2juo$1 digitaldaemon.com>, Mark Evans says...
I cut my baby programmer teeth on Lisp.... 
I also write a LOT of C, and some C++.
In all the C code I've written, I haven't missed Lisp's first class 
functions.  Not once.

Well McCarthy, the creator of Lisp, got some things wrong. http://www.cs.brown.edu/courses/cs173/2001/Lectures/2001-09-21.pdf It's also possible that you were never a good Lisp programmer.

Well, I probably don't rate as a great lisp programmer... I once tried to get a group of engineers to use a Scheme interpreter I wrote to control a place and route tool I was working on. Big mistake. I junked it, and wrote a Basic interpreter instead which they actually used (this was before TCL). Ever since, I've been weary of language features that confuse engineers. Imagine trying to teach an average group of guys in the industry about tail recursion instead of loops, or continuations for error handling. Can you give me a example of how first class functions can be used to improve an average programmer's productivity without confusing him or the poor guy who will inherit his code? Personally, I think we do most programmers a favor by simplifying computer languages while adding a minimum of new features. I love that Java doesn't have pointers, and that D discourages them. I think all pointers, including function pointers and delegates, are like the C proprocessor: you don't really need them if the language provides the capabilities you were trying to emulate directly. Bill
Feb 21 2003
prev sibling next sibling parent reply Mark Evans <Mark_member pathlink.com> writes:
The author deliberates between C, C++, Java, OCaml, Scheme, Lisp.  Maybe I
should have put the subject as "Re: OCaml" but that was getting tired.  -M.

http://www.paulgraham.com/vanlfsp.html

'Writing Java code, though not particulary painful in the sense that C is
painful (core dumps etc.), puts me to sleep. Writing Ocaml ... is exciting. My
motivation to tackle the project has tripled overnight.... Why are "languages
designed for smart people" (LFSPs) so much more fun to program in than
"languages designed for the masses" (LFMs)?'
Feb 21 2003
next sibling parent bill viasic.com writes:
In article <b370f0$a7r$1 digitaldaemon.com>, Mark Evans says...
The author deliberates between C, C++, Java, OCaml, Scheme, Lisp.  Maybe I
should have put the subject as "Re: OCaml" but that was getting tired.  -M.

http://www.paulgraham.com/vanlfsp.html

'Writing Java code, though not particulary painful in the sense that C is
painful (core dumps etc.), puts me to sleep. Writing Ocaml ... is exciting. My
motivation to tackle the project has tripled overnight.... Why are "languages
designed for smart people" (LFSPs) so much more fun to program in than
"languages designed for the masses" (LFMs)?'

Yes, languages for smart people are more fun. However, nearly all software that sell well, and even most open-source code, is eventually worked on by the other kind of people. This is why GNU recommends staying away from C++, and contributing code in plain old C. The real trick is making the language as powerful as possbile, while keeping the compiler lean, and keeping those other kinds of people from shooting themselves in the foot. Bill P.S. I happen to specialize in keeping programmers' feet healthy.
Feb 21 2003
prev sibling parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
I feel like that burned out hacker he talks about.

I need a new language in a bad way.  C++ is getting really really old.  I
find myself fighting the language more than focusing on the original
problem.  Hell most of my problems are caused directly by the implementation
language and the crystal structure that C++ programs naturally solidify into
as they grow.

I grow bored with the problem by the time I get halfway through implementing
its solution, or a deadline comes along and it has to be put on hold until I
forget about it, or until the feature gets dropped due to lack of time.

Maybe it's just me.  But I really am not all that excited about programming
anymore.  A new language that gave me lots of expressive power while
simultaneously freeing me from the mundane worries of memory management and
cleanup and type checking and syntactical nitpicking would be a godsend.

Maybe I should check out OCaml more.  I looked at it but it seems, how shall
I put it, a little inelegant.  I don't have much time for learning languages
anymore.  It's hard to decide which one to pursue.

Sean

"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b370f0$a7r$1 digitaldaemon.com...
 The author deliberates between C, C++, Java, OCaml, Scheme, Lisp.  Maybe I
 should have put the subject as "Re: OCaml" but that was getting

 http://www.paulgraham.com/vanlfsp.html

 'Writing Java code, though not particulary painful in the sense that C is
 painful (core dumps etc.), puts me to sleep. Writing Ocaml ... is

 motivation to tackle the project has tripled overnight.... Why are

 designed for smart people" (LFSPs) so much more fun to program in than
 "languages designed for the masses" (LFMs)?'

Feb 22 2003
parent reply Bill Cox <bill viasic.com> writes:
Sean L. Palmer wrote:
 I feel like that burned out hacker he talks about.
 
 I need a new language in a bad way.  C++ is getting really really old.  I
 find myself fighting the language more than focusing on the original
 problem.  Hell most of my problems are caused directly by the implementation
 language and the crystal structure that C++ programs naturally solidify into
 as they grow.

Man, I'm with you there... I've gotten so frustrated, I've even written my own language to solve the issues I've been fighting forever. I have the authority to make our company use it... but even if it doubles our productivity, that would probably be stupid. D is remarkably close to what I have been working on, and I think it has a real chance of success. If it could just support directed graphs well, I'd be happy. Bill
Feb 22 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3E57BCC7.6050301 viasic.com...
 If it could just support directed graphs well, I'd be happy.

Could you elaborate, please? (I apologize if you have before.)
Feb 22 2003
parent reply Bill Cox <bill viasic.com> writes:
Hi, Walter.

Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E57BCC7.6050301 viasic.com...
 
If it could just support directed graphs well, I'd be happy.

Could you elaborate, please? (I apologize if you have before.)

Sure. It's somewhat complicated. I wish I could sumarize the problems in one or two lines, but I can't. Just to jump ahead, I think a good solution can be found in Sather. Their "reuse" construct looks easy to implement (of course, templates looked easy too...). Ken Carpenter's suggested "framwork" idea seems to also work well. If you look at the non-reusable pseudo-code I posted for the Pizza Contest, I think you'll find it both readable, and likely to lead to an efficient implementation (Ok, I haven't compiled it yet... you'll probably find that I've got glaring errors). I think when you see the reusable versions people hopefully will write for the contest, you'll see that they are either very complex, or not very efficient. With a "reuse" construct, I think you could directly reuse the simple and otherwise non-reusable version. First, let's look at why the pseudo code I suggested is not reusable in D. This is simple. Inheriting from Node, Edge, and Graph is the only way to reuse this code, since it wasn't defined as an interface or template. If Netlist were to inherit from Graph, it would inherit a linked list of nodes, but what I asked for was two doubly linked lists, one of Instances, and one of Nets. Similar problems occur with the other classes. We also run into the problem of having to do lots casts to derived classes if we ever want to traverse the derived objects. Let's try that again, but this time with templates. Graph, Node, and Edge could all be rewritten to be template classes, and the container classes could be provided by the user. But all that does is let us define various kinds of directed graphs. It doesn't allow me to directly embed graph functionality in my netlist. The two doubly linked lists in Netlist are not easily going to get defined by using the Graph template class. You'd have to do something goofy like inherit from two versons of the Graph template at the same time. It's all down-hill from there. Ken Carpenter suggested making Graph, Node, and Edge template classes that inherit from template parameters. This may actually lead to the winning implementation, but I think it's going to be pretty convoluted. Frankly, if a programmer didn't shoot himself in the foot with such code, I'd buy a gun and shoot it for him. How about using interfaces? This actually works, but has some issues. Now we have to define a large interface that mimics every method and attribute used in the pseudo code. It could be dozens of methods. Every one of them has to be defined by the user. Worse, every time I add a graph related atribute or method to the Graph interface, every user has to upgrade his code, even if he doesn't need the new graph functionallity. There are all kinds of attributes that would eventually be needed. For example, we have a level attribute in our simple code for the contest. There are other problems. The foreach(Graph, node) functionality would have to be done with some sort of virtual iterator. When writing the foreach loop in the Graph code, you can't just instantiate the iterator on the stack as you would in C++, because you don't know it's size. That's determined by the user's choice of contaner class, which is hidden behind the interface. You have to use something like Java Enumeration interfaces, which leads to pretty slow code. The darned iterators are going to wind up on the heap! Finally, there's the potential overhead of lots of virtual function calls since everything is done through an interface. However, if the D compiler were to do global optimizations across modules, it might succeed in binding most of them statically. It seems to me that writing a good reusable graph module in D is hard. I think it should make for an interesting contest, if I can get any competitors interested. If someone could show me how to do a really good one that D specifically enables, I think I'd ask my company to start using D, since we currently have to rewrite basic code like this every day in C. I haven't used the Sather "reuse" constructs before, so I don't know what hidden pitfalls are there. However, it seems to mimic what I do today in C: copy the functions and class attributes from one module and paste them into my new module, and then rename things to make it all work. It's very similar to the "framwork" stuff Ken Carpenter was talking about, which also seems like it would do the trick. I sure hope I'm wrong about all this, and someone just shows me how to reuse code... It would definately be worth the 30 bucks for pizza. Bill
Feb 22 2003
next sibling parent reply Patrick Down <pat codemoon.com> writes:
Bill Cox <bill viasic.com> wrote in news:3E57E58F.4080108 viasic.com:

 Hi, Walter.
 
 Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E57BCC7.6050301 viasic.com...
 
If it could just support directed graphs well, I'd be happy.

Could you elaborate, please? (I apologize if you have before.)

Sure. It's somewhat complicated. I wish I could sumarize the problems in one or two lines, but I can't. Just to jump ahead, I think a good solution can be found in Sather. Their "reuse" construct looks easy to implement (of course, templates looked easy too...). Ken Carpenter's suggested "framwork" idea seems to also work well.

Actually it was me but to give credit where credit is due I got the the framework idea from an article by Tim Sweeney. http://www.gamespy.com/legacy/articles/devweek_b.shtm A notable quote is... <quote> While object-oriented languages handled pure objects well, they modeled complex relationships between objects poorly. Frameworks and collections turn out not to be truly modular or extensible because the languages can't represent families of objects. </quote>
Feb 22 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Patrick Down" <pat codemoon.com> wrote in message
news:Xns932AB5EFBBD40patcodemooncom 63.105.9.61...
 Actually it was me but to give credit where credit is due I got the
 the framework idea from an article by Tim Sweeney.

 http://www.gamespy.com/legacy/articles/devweek_b.shtm

A great read. The article lists as a new requirement: "The language needs to support "function references bound to specific objects;" such entities (unsupported in C++ and Java) are the essential glue for binding parametric components together; without them, you often have to write an enormous amount of "duct tape" code to hold a framework together." D does this with delegates. I didn't really understand what they were talking about with inner classes, and why the same effect could not be achieved by simply adding a pointer to a class as a member of the framework class.
Feb 22 2003
parent reply Bill Cox <bill viasic.com> writes:
Walter wrote:
 "Patrick Down" <pat codemoon.com> wrote in message
 news:Xns932AB5EFBBD40patcodemooncom 63.105.9.61...
 
Actually it was me but to give credit where credit is due I got the
the framework idea from an article by Tim Sweeney.

http://www.gamespy.com/legacy/articles/devweek_b.shtm

A great read. The article lists as a new requirement: "The language needs to support "function references bound to specific objects;" such entities (unsupported in C++ and Java) are the essential glue for binding parametric components together; without them, you often have to write an enormous amount of "duct tape" code to hold a framework together." D does this with delegates. I didn't really understand what they were talking about with inner classes, and why the same effect could not be achieved by simply adding a pointer to a class as a member of the framework class.

Hi. I agree, it's a really good artical. I tend to focus more on what he calls "virtual classes", more than delegates. I haven't ever seemed to need delegates, so I'm unfamiliar with the problem he's solving. If I read it right, "virtual classes" are simply classes that can be replaced (just like virtual functions). You define a higher level containing class, inherit the whole thing, and replace classes that need custom definitions for your app. A lot of programmers and languages use the concept of a class to replace the concept of a module. Personally, I prefer a module to be named a "module", and the classes within "classes". If you rename entities a bit, I think you'll see that Patrick Down's "frameworks" and "virtual classes" are essentially the same thing. As far as I can tell, they are also very similar to Sather's "reuse" construct. All of these have one thing in common: They let me inherit all the code in a module into my module, while letting me replace the things that don't work for me. This is very much like class inheritance, where I get to fix the methods by overriding them. However, it applies at a module level. I think this is what it takes to reuse code with multiple inter-relating classes cleanly. Of these concepts, Sather's reuse concept seems to me to be the most straight-forward to implement. It also seems easier to explain to people. I wouldn't like to have to teach "virtual classes" to new programmers. However the "reuse" stuff looks like what they already do: copy, paste, and edit. I can explain it in terms of actions rather than higher-level polymorphism. On the other hand, a lot of C++ programmers might give D a serious look if they though they could achieve higher level polymorphism through virtual classes. Marketing is everything. Mabe D should incorporate Strategic Programming, too :-) Bill
Feb 22 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3E584E7A.2060908 viasic.com...
 If I read it right, "virtual classes" are simply classes that can be
 replaced (just like virtual functions).  You define a higher level
 containing class, inherit the whole thing, and replace classes that need
 custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?
 A lot of programmers and languages use the concept of a class to replace
 the concept of a module.  Personally, I prefer a module to be named a
 "module", and the classes within "classes".

So do I. I discovered quite by accident that the module concept makes the C++ concept of "friends" irrelevant. That was a nice surprise. Modules are so much more natural.
 If you rename entities a bit, I think you'll see that Patrick Down's
 "frameworks" and "virtual classes" are essentially the same thing.  As
 far as I can tell, they are also very similar to Sather's "reuse"
 construct.  All of these have one thing in common:  They let me inherit
 all the code in a module into my module, while letting me replace the
 things that don't work for me.  This is very much like class
 inheritance, where I get to fix the methods by overriding them.
 However, it applies at a module level.

 I think this is what it takes to reuse code with multiple inter-relating
 classes cleanly.

Yup, the 'friend' issue.
 Of these concepts, Sather's reuse concept seems to me
 to be the most straight-forward to implement.  It also seems easier to
 explain to people.  I wouldn't like to have to teach "virtual classes"
 to new programmers.  However the "reuse" stuff looks like what they
 already do: copy, paste, and edit.  I can explain it in terms of actions
 rather than higher-level polymorphism.

 On the other hand, a lot of C++ programmers might give D a serious look
 if they though they could achieve higher level polymorphism through
 virtual classes.  Marketing is everything.  Mabe D should incorporate
 Strategic Programming, too :-)

I think I'll just find a way to bury all those buzzwords into the D spec so that D pops up when people google on them <g>.
Feb 23 2003
next sibling parent Andy Friesen <andy ikagames.com> writes:
Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E584E7A.2060908 viasic.com...
 
If I read it right, "virtual classes" are simply classes that can be
replaced (just like virtual functions).  You define a higher level
containing class, inherit the whole thing, and replace classes that need
custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?

I think the idea is that Foo could just use Bar instances without regard for polymorphism, and it would all just work if you subclassed Foo and Bar. Existing Foo methods would use the derived class. class Baz : Foo { class Bleagh : Bar { ... } // Foo methods will use Bleagh instead of Bar } In languages like D, this is a simple matter of using a method of Foo as a factory; subclass and override that to return new instances of your derived class, and you're gold. Override the factory, and everything uses the new inner class.
 
A lot of programmers and languages use the concept of a class to replace
the concept of a module.  Personally, I prefer a module to be named a
"module", and the classes within "classes".

So do I. I discovered quite by accident that the module concept makes the C++ concept of "friends" irrelevant. That was a nice surprise. Modules are so much more natural.
If you rename entities a bit, I think you'll see that Patrick Down's
"frameworks" and "virtual classes" are essentially the same thing.  As
far as I can tell, they are also very similar to Sather's "reuse"
construct.  All of these have one thing in common:  They let me inherit
all the code in a module into my module, while letting me replace the
things that don't work for me.  This is very much like class
inheritance, where I get to fix the methods by overriding them.
However, it applies at a module level.

I think this is what it takes to reuse code with multiple inter-relating
classes cleanly.

Yup, the 'friend' issue.
Of these concepts, Sather's reuse concept seems to me
to be the most straight-forward to implement.  It also seems easier to
explain to people.  I wouldn't like to have to teach "virtual classes"
to new programmers.  However the "reuse" stuff looks like what they
already do: copy, paste, and edit.  I can explain it in terms of actions
rather than higher-level polymorphism.

On the other hand, a lot of C++ programmers might give D a serious look
if they though they could achieve higher level polymorphism through
virtual classes.  Marketing is everything.  Mabe D should incorporate
Strategic Programming, too :-)

I think I'll just find a way to bury all those buzzwords into the D spec so that D pops up when people google on them <g>.

Feb 23 2003
prev sibling next sibling parent Patrick Down <pat codemoon.com> writes:
"Walter" <walter digitalmars.com> wrote in
news:b3a0o8$2sbt$1 digitaldaemon.com: 

 
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E584E7A.2060908 viasic.com...
 If I read it right, "virtual classes" are simply classes that can be
 replaced (just like virtual functions).  You define a higher level
 containing class, inherit the whole thing, and replace classes that
 need custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?

I think you missed the point. He was not talking about one class containing another. The framework provides a context in which all the classes in it may be overridden by inheritance and all the classes will still retain the same relationships with each other. class A { B b } class B { C c } class C { } Here A, B and C have a defined relationship with one another. class D : A {} class E : B {} class F : C {} Now D doesn't own an E it owns a B. D, E and F don't have the same relationship to each other the A, B and C do. Sometimes this is what you want but sometimes what you want is the relationship of A, B and C to be a abstract pattern for a concrete implementation ion of E, D and F. Let's take Bill Cox's Graph library as an more concrete example. Graph, Node and Edge are related to one another. There are graph algorithms in the library that advantage of these relations to do certain tasks. Finding shortest path between two nodes is an example. class Graph { void shortestPath(Node from, Node to, out Node[] pathNodes, out Edge[] pathEdges); } class Edge { int getWeight(); Node getFrom(); Node getTo(); } class Node { Edge[] getEdges(); } class Road : Edge { char[] getName(); } class City : Node { char[] getName(); } Graph usa = new Graph... City[] stops; Road[] route; // ERROR shortestPath wants Node[] and Edge[] // not City[] and Road[] usa.shortestPath(boston,los_angles,stops,route); You can get around this with some nasty casting. Templates can supply a solution too. There is an example of this in the "Directed Graph Support" thread. But it's clunky. The framework way of doing this would be. framework GraphLib { class Graph { void shortestPath(Node from, Node to, out Node[] pathNodes, out Edge[] pathEdges); } class Edge { int getWeight(); Node getFrom(); Node getTo(); } class Node { Edge[] getEdges(); } } framework Map : GraphLib { class Edge { char[] getName(); } class Node { char[] getName(); } } The Map framework brings forward the implementation of all the classes in GraphLib and extends them. I see framework as more of a template definition. GraphLib provides a pattern that can be extended. It might even be recast into the template syntax. Like this... template GraphLib { class Graph { void shortestPath(Node from, Node to, out Node[] pathNodes, out Edge[] pathEdges); } class Edge { int getWeight(); Node getFrom(); Node getTo(); } class Node { Edge[] getEdges(); } } instance GraphLib MyGraph { // Append this definition to GraphLib's // Edge and node definition class Edge { char[] getName(); } class Node { char[] getName(); } }
Feb 23 2003
prev sibling next sibling parent reply Bill Cox <bill viasic.com> writes:
Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E584E7A.2060908 viasic.com...
 
If I read it right, "virtual classes" are simply classes that can be
replaced (just like virtual functions).  You define a higher level
containing class, inherit the whole thing, and replace classes that need
custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?

I can try to use both techniques to inherit graph functionality into a hyper-graph, and let you know how I did. I find a concrete example can help solidify things. It might take me a couple of days to get around to it. Bill
Feb 23 2003
parent reply Bill Cox <bill viasic.com> writes:
Bill Cox wrote:
 Walter wrote:
 
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E584E7A.2060908 viasic.com...

 If I read it right, "virtual classes" are simply classes that can be
 replaced (just like virtual functions).  You define a higher level
 containing class, inherit the whole thing, and replace classes that need
 custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?

I can try to use both techniques to inherit graph functionality into a hyper-graph, and let you know how I did. I find a concrete example can help solidify things. It might take me a couple of days to get around to it. Bill

I've messed around with reusing a simple graph package a bit, and now have a simple example. The following code is from my toy compiler I've been playing with (which I call "Sail"). The 'reuse' construct is the same as Sather's "include" construct. It's also similar to the "framework" Patrick Down proposed, and "virtual classes", and Eiffel's "covariation". I like it because it puts the code needed to reuse the graph package to one place. My second favorite is Patrick's frameworks, which read very nicely. Here's a simple piece of graph code in Sail. It parses, but I haven't implemented the reuse stuff yet, so it doesn't run. The code just detects loops in directed graphs: module graph; class Graph { // We have a linked list of nodes, and nodes point back // to their graph. cascade LinkedList of Node nodes:graph; bool findLoop() { Node node; clearNodeFlags(); // This itterator gets generated by the LinkedList code foreach(nodes, node) { if(!node.visited && node.findLoop()) { return true; } } return false; } clearNodeFlags() { Node node; foreach(nodes, node) { node.visited = false; node.marked = false; } } } class Node { // This adds two linked-list containters to Node, and two back // pointers to Node from Edge. cascade LinkedList of Edge outEdges:fromNode, inEdges:toNode; bool visited, marked; findLoop() { Node otherNode; Edge edge; visited = true; marked = true; foreach(outEdges, edge) { // The fromNode.owner member of Edge is generated by // the linked-list outEdges relationship. otherNode = edge.fromNode.owner; if(otherNode.marked || !otherNode.visited && otherNode.findLoop()) { marked = false; return true; } } marked = false; return false; } } class Edge { // No fields are declared here, but the Node back-pointers are added // by the linked-list containers in Node. } Now lets reuse the code in a realistic application, a simple PCB router. A printed circuit board has layers of wires, interconnected by vias. Net's are a collection of these wires, which interconnect components on the board. I just list the Net, Wire, and Via classes, but their would be others to model the whole board. module router; class Net { // We have a doubly linked list of wires, and wires point back // to their nets. cascade DoublyLinkedList of Wire wires:net; } class Wire { // We have an undirected graph of wires connected by vias. // This still requires two containers, abitrarily called // via1s and via2s. cascade LinkedList of Via via1s:wire1, via2s:wire2; } class Via { } Note that this sub-schema of classes is isomorphic to the schema for directed graphs. (Schema just means a diagram of classes drawn as nodes, and relationships drawn as edges. Schemas are isomorphic if they are basically the same graph, just with names changed.) To reuse all the graph stuff, I need only specify the mapping of classes and relationships between the modules: reuse graph { // Nets act like Graphs Graph : Net; // The wires relationship acts like the nodes relationship Graph.nodes : Net.wires; Node : Route; Node.outEdges : Route.via1s; Node.inEdges : Route.via2s; Edge : Via; } Now, I can determine if a Net has a loop with net.findLoop(). Note that I could include graph functionality multiple times if needed, since there may be multiple isomorphisms with sub-schemas of my module. This code causes all the graph module's code to be included in the router module. During the copy, we replace or rename identifiers as specified in the mapping. Unmapped identifiers are copied as-is. Without a construct of this kind, we are left with templates, interfaces, and inheritance to try to reuse the graph package. So far as I can tell, none of these work well for this kind of code reuse. Patrick's "frameworks" work perfectly well here. Frameworks look more like an inheritance mechanism, while this "reuse" construct looks more like a fancy preprocessor thing where we include code, but replace some things. Sather calls it "include", but is otherwise identical to this "reuse" construct. I think "include" would possibly confuse C programmers, but perhaps it would give them the right notion. Bill
Feb 24 2003
parent Bill Cox <bill viasic.com> writes:
The reuse construct should have read:

reuse graph {
     // Nets act like Graphs
     Graph : Net;
     // The wires relationship acts like the nodes relationship
     Graph.nodes : Net.wires;
     Node : Wire;
     Node.outEdges : Wire.via1s;
     Node.inEdges : Wire.via2s;
     Edge : Via;
}

That's the problem with untested code... It's never right.

I just work on this thing for fun, but I hope to eventually implement 
full support for the reuse construct.  If it would help, I could do it 
sooner than later, and post what kind of trouble I run into.

Bill
Feb 24 2003
prev sibling next sibling parent Bill Cox <bill viasic.com> writes:
Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E584E7A.2060908 viasic.com...
 
If I read it right, "virtual classes" are simply classes that can be
replaced (just like virtual functions).  You define a higher level
containing class, inherit the whole thing, and replace classes that need
custom definitions for your app.

That's the way I read it, too, but how is it different from (in C++): class Foo { class Bar *p; }; where you can inherit from Foo, derive from Bar, and replace p?

I'll try out both methods and post how it goes. It will probably take a couple days to get to it. Bill
Feb 23 2003
prev sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
In article <b3a0o8$2sbt$1 digitaldaemon.com>, Walter says...
That's the way I read it, too, but how is it different from (in C++):

    class Foo
    {
        class Bar *p;
    };

where you can inherit from Foo, derive from Bar, and replace p?

Because now in your class inherited from Foo, you can only refer to p as a Bar (not the inherited type) unless you litter your code with type-casts. This can be a major source of type incompabilities and bugs. Eiffel prominently features a fix for this conceptual problem; they call it "covariation". When you inherit from Foo, you can declare p as a member with a new type, but only if the type is Bar or a subclass of Bar. It will then completely replace Foo's p. I'm not sure if you could do this in D. It seems that you would run into problems in Foo's methods, for example if Foo's constructor is called on a subclass that replaces p, it might attempt to allocate a Bar instead of the appropriate subclass of Bar. You can fix this incurring some performance lossage by using the properties methods in D or setter/getters in C++: instead of referring to p directly set and get p through a method that subclasses of Foo will override. That is really the idea lurking behind Sweeney's "virtual classes" concept. I do agree that this problem can be a major constraint on large object-centric programs. Dan
Feb 23 2003
parent "Walter" <walter digitalmars.com> writes:
Thanks, your explanation makes sense to me. -Walter

"Dan Liebgold" <Dan_member pathlink.com> wrote in message
news:b3blva$17h2$1 digitaldaemon.com...
 In article <b3a0o8$2sbt$1 digitaldaemon.com>, Walter says...
That's the way I read it, too, but how is it different from (in C++):

    class Foo
    {
        class Bar *p;
    };

where you can inherit from Foo, derive from Bar, and replace p?

Because now in your class inherited from Foo, you can only refer to p as a

 (not the inherited type) unless you litter your code with type-casts. This

 be a major source of type incompabilities and bugs.

 Eiffel prominently features a fix for this conceptual problem; they call

 "covariation". When you inherit from Foo, you can declare p as a member

 new type, but only if the type is Bar or a subclass of Bar.  It will then
 completely replace Foo's p.

 I'm not sure if you could do this in D. It seems that you would run into
 problems in Foo's methods, for example if Foo's constructor is called on a
 subclass that replaces p, it might attempt to allocate a Bar instead of

 appropriate subclass of Bar.

 You can fix this incurring some performance lossage by using the

 methods in D or setter/getters in C++: instead of referring to p directly

 and get p through a method that subclasses of Foo will override. That is

 the idea lurking behind Sweeney's "virtual classes" concept.

 I do agree that this problem can be a major constraint on large

 programs.

 Dan

Feb 24 2003
prev sibling parent reply Bill Cox <bill viasic.com> writes:
Patrick Down wrote:
 Bill Cox <bill viasic.com> wrote in news:3E57E58F.4080108 viasic.com:
 
 
Hi, Walter.

Walter wrote:

"Bill Cox" <bill viasic.com> wrote in message
news:3E57BCC7.6050301 viasic.com...


If it could just support directed graphs well, I'd be happy.

Could you elaborate, please? (I apologize if you have before.)

Sure. It's somewhat complicated. I wish I could sumarize the problems in one or two lines, but I can't. Just to jump ahead, I think a good solution can be found in Sather. Their "reuse" construct looks easy to implement (of course, templates looked easy too...). Ken Carpenter's suggested "framwork" idea seems to also work well.

Actually it was me but to give credit where credit is due I got the the framework idea from an article by Tim Sweeney.

Oops... Sorry Patrick. Ken suggested the pizza link.
 http://www.gamespy.com/legacy/articles/devweek_b.shtm
 
 A notable quote is...
 <quote>
 While object-oriented languages handled pure objects well, they modeled
 complex relationships between objects poorly. Frameworks and collections
 turn out not to be truly modular or extensible because the languages
 can't represent families of objects. </quote>

This is the short version of what goes wrong representing graphs. With only one class, like with a binary tree, you're in good shape. As soon as the data structures involve multiple inter-related classes, reuse gets hard. Bill
Feb 22 2003
parent "Ken Carpenter" <kencr shaw.ca> writes:
"Bill Cox" <bill viasic.com> wrote in message
news:3E58454F.7030500 viasic.com...
 Oops... Sorry Patrick.  Ken suggested the pizza link.

I was trying to think back and remember mentioning anything about a framework to you! I almost convinced myself that I might have, since I've done something similar with a code generator I wrote at work. :-) Ken Carpenter
Feb 23 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
I suspect that templates are the answer, but I haven't really thought
through applying it to the problem you pose.

"Bill Cox" <bill viasic.com> wrote in message
news:3E57E58F.4080108 viasic.com...
 Hi, Walter.

 Walter wrote:
 "Bill Cox" <bill viasic.com> wrote in message
 news:3E57BCC7.6050301 viasic.com...

If it could just support directed graphs well, I'd be happy.

Could you elaborate, please? (I apologize if you have before.)

Sure. It's somewhat complicated. I wish I could sumarize the problems in one or two lines, but I can't. Just to jump ahead, I think a good solution can be found in Sather. Their "reuse" construct looks easy to implement (of course, templates looked easy too...). Ken Carpenter's suggested "framwork" idea seems to also work well. If you look at the non-reusable pseudo-code I posted for the Pizza Contest, I think you'll find it both readable, and likely to lead to an efficient implementation (Ok, I haven't compiled it yet... you'll probably find that I've got glaring errors). I think when you see the reusable versions people hopefully will write for the contest, you'll see that they are either very complex, or not very efficient. With a "reuse" construct, I think you could directly reuse the simple and otherwise non-reusable version. First, let's look at why the pseudo code I suggested is not reusable in D. This is simple. Inheriting from Node, Edge, and Graph is the only way to reuse this code, since it wasn't defined as an interface or template. If Netlist were to inherit from Graph, it would inherit a linked list of nodes, but what I asked for was two doubly linked lists, one of Instances, and one of Nets. Similar problems occur with the other classes. We also run into the problem of having to do lots casts to derived classes if we ever want to traverse the derived objects. Let's try that again, but this time with templates. Graph, Node, and Edge could all be rewritten to be template classes, and the container classes could be provided by the user. But all that does is let us define various kinds of directed graphs. It doesn't allow me to directly embed graph functionality in my netlist. The two doubly linked lists in Netlist are not easily going to get defined by using the Graph template class. You'd have to do something goofy like inherit from two versons of the Graph template at the same time. It's all down-hill from there. Ken Carpenter suggested making Graph, Node, and Edge template classes that inherit from template parameters. This may actually lead to the winning implementation, but I think it's going to be pretty convoluted. Frankly, if a programmer didn't shoot himself in the foot with such code, I'd buy a gun and shoot it for him. How about using interfaces? This actually works, but has some issues. Now we have to define a large interface that mimics every method and attribute used in the pseudo code. It could be dozens of methods. Every one of them has to be defined by the user. Worse, every time I add a graph related atribute or method to the Graph interface, every user has to upgrade his code, even if he doesn't need the new graph functionallity. There are all kinds of attributes that would eventually be needed. For example, we have a level attribute in our simple code for the contest. There are other problems. The foreach(Graph, node) functionality would have to be done with some sort of virtual iterator. When writing the foreach loop in the Graph code, you can't just instantiate the iterator on the stack as you would in C++, because you don't know it's size. That's determined by the user's choice of contaner class, which is hidden behind the interface. You have to use something like Java Enumeration interfaces, which leads to pretty slow code. The darned iterators are going to wind up on the heap! Finally, there's the potential overhead of lots of virtual function calls since everything is done through an interface. However, if the D compiler were to do global optimizations across modules, it might succeed in binding most of them statically. It seems to me that writing a good reusable graph module in D is hard. I think it should make for an interesting contest, if I can get any competitors interested. If someone could show me how to do a really good one that D specifically enables, I think I'd ask my company to start using D, since we currently have to rewrite basic code like this every day in C. I haven't used the Sather "reuse" constructs before, so I don't know what hidden pitfalls are there. However, it seems to mimic what I do today in C: copy the functions and class attributes from one module and paste them into my new module, and then rename things to make it all work. It's very similar to the "framwork" stuff Ken Carpenter was talking about, which also seems like it would do the trick. I sure hope I'm wrong about all this, and someone just shows me how to reuse code... It would definately be worth the 30 bucks for pizza. Bill

Feb 22 2003
prev sibling parent reply "Robert M. Münch" <robert.muench robertmuench.de> writes:
"Bill Cox" <bill viasic.com> schrieb im Newsbeitrag
news:3E57BCC7.6050301 viasic.com...

 If it could just support directed graphs well, I'd be happy.

Hi, I'm very interested in this graph stuff as well. But sorry, I can't code it for some pizza ;-)) even it would be a lot of fun. Anyway, graphs are on my todo list for some other project I need them for. I highly suggest to take a look at these links: http://www.mpi-sb.mpg.de/LEDA/leda.html http://www.algorithmic-solutions.de/leda.htm I have used the LEDA graph stuff some years ago. Very advanced and well done. Easy to use as plug-in etc. That's the concept I want to use to do it in D. What I'm mostly interested in is doing persistens graphs and traversal of persistens graphs. Perhaps using Berkely DB as base... Just thinking loud. -- Robert M. Münch IT & Management Freelancer Mobile: +49 (0)177 2452 802 Fax : +49 (0)721 8408 9112 Web : http://www.robertmuench.de
Feb 23 2003
parent reply Bill Cox <bill viasic.com> writes:
Hi, Robert, and Thanks for the links.

Robert M. Münch wrote:
 "Bill Cox" <bill viasic.com> schrieb im Newsbeitrag
 news:3E57BCC7.6050301 viasic.com...
 
 
If it could just support directed graphs well, I'd be happy.

Hi, I'm very interested in this graph stuff as well. But sorry, I can't code it for some pizza ;-)) even it would be a lot of fun. Anyway, graphs are on my todo list for some other project I need them for. I highly suggest to take a look at these links: http://www.mpi-sb.mpg.de/LEDA/leda.html http://www.algorithmic-solutions.de/leda.htm I have used the LEDA graph stuff some years ago. Very advanced and well done. Easy to use as plug-in etc. That's the concept I want to use to do it in D. What I'm mostly interested in is doing persistens graphs and traversal of persistens graphs. Perhaps using Berkely DB as base... Just thinking loud.

It sounds like they have some good software. Their "Network" algorithm components sound like the kind of thing I do a lot. I read some of their on-line documentation. You have to create graphs in their database, run their algorthms, and then read out the results. It's not really reusable code. For example, you couldn't use it to add graph functionality to hyper-graphs. Bill
Feb 23 2003
parent "Robert M. Münch" <robert.muench robertmuench.de> writes:
"Bill Cox" <bill viasic.com> schrieb im Newsbeitrag
news:3E590E6E.4050204 viasic.com...

 It sounds like they have some good software.  Their "Network" algorithm
 components sound like the kind of thing I do a lot.

Hi, yes their algorithms are very advanced.
 I read some of their on-line documentation.  You have to create graphs
 in their database, run their algorthms, and then read out the results.
 It's not really reusable code.  For example, you couldn't use it to add
 graph functionality to hyper-graphs.

Really? Hm... must have changed radical since last time I used it. Normaly you get a set of classes and than make your way. But I have to say I didn't had a closer look into the online documentation. Robert
Feb 25 2003
prev sibling parent reply Mark Evans <Mark_member pathlink.com> writes:
Brief but informative slides on the proper compilation of function closures. -M.

http://pauillac.inria.fr/~xleroy/talks/compilation-agay.pdf
Feb 21 2003
next sibling parent reply Mark Evans <Mark_member pathlink.com> writes:
A must read from Paul Graham.  I could not have offered a better rationale for
first-class functions, though the principle stated is general, and so deserves
its own thread.

The design goals of D put certain constraints on the full development of this
idea, but the ceiling is a lot higher than anyone involved with D really
understands.  Vault's decision to use first-class functions is one evidence of
that fact.  -M.


http://www.paulgraham.com/power.html
http://www.paulgraham.com/fix.html

"It seems to me that succinctness is what programming languages are for.
Computers would be just as happy to be told what to do directly in machine
language. I think that the main reason we take the trouble to develop high-level
languages is to get leverage, so that we can say (and more importantly, think)
in 10 lines of a high-level language what would require 1000 lines of machine
language. In other words, the main point of high-level languages to make source
code smaller."

"The main value of the succinctness test is as a guide in designing languages.
The most useful comparison between languages is between two potential variants
of the same language. What can I do in the language to make programs shorter?"

"Aiming for succinctness seems a good way to find new ideas. If you can do
something that makes many different programs shorter, it is probably not a
coincidence: you have probably discovered a useful new abstraction."

"...programs written in more powerful languages tend to have fewer bugs."
Feb 21 2003
next sibling parent bill viasic.com writes:
Hi, Mark.

Great links!  The second one is the funniest computer language related page I
ever read.

http://www.paulgraham.com/power.html
http://www.paulgraham.com/fix.html

I agree for the need of powerful constructs. The smoke test for a language's power that I use is a simple reusable directed graph package. Every popular efficiently compiled language I've tried it in has failed to elegantly support it! We've talked a about it on this newsgroup, and haven't come up with a clean solution in D. In C and C++, I write the same stupid isomorphic functions over and over and over... Want to break loops in a directed graph in a single linear traversal? I've written it dozens of times. How about finding a max weighted path from primary inputs to outputs (representing circuit delay)? It hurts every time I write it. The types change, but never the algorithms. Bill
Feb 21 2003
prev sibling next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b37347$cdr$1 digitaldaemon.com...
 http://www.paulgraham.com/fix.html

D: C++ is too complicated
Feb 22 2003
parent reply Mark T <Mark_member pathlink.com> writes:
In article <b38jlm$1nb9$1 digitaldaemon.com>, Walter says...
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b37347$cdr$1 digitaldaemon.com...
 http://www.paulgraham.com/fix.html

D: C++ is too complicated

Feb 23 2003
parent reply "Ken Carpenter" <kencr shaw.ca> writes:
"Mark T" <Mark_member pathlink.com> wrote in message
news:b3aonm$dpc$1 digitaldaemon.com...
 In article <b38jlm$1nb9$1 digitaldaemon.com>, Walter says...
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b37347$cdr$1 digitaldaemon.com...
 http://www.paulgraham.com/fix.html

D: C++ is too complicated


Many people hear "C# uses a VM" and assume that it's the same as Java. Just to clarify, C# and other .NET languages are first compiled to a "VM" code (CIL), but they are then compiled to native code before they are executed. Ken Carpenter
Feb 23 2003
next sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
D: C++ is too complicated


Many people hear "C# uses a VM" and assume that it's the same as Java. Just to clarify, C# and other .NET languages are first compiled to a "VM" code (CIL), but they are then compiled to native code before they are executed.

Java VM's are not all JIT (compile before) some are dynamic compilers (compile if its used more than once as compilation + execute time can be longer than interpret once time) also this allows the true main line of the code to be compiled. with C compilers 'if' is usally compiled as branch over the if clause, with a dynamic compiler if the if cluase is not entered then it is compiled as a branch out of the main line to the if clause making the common case code faster (missed branches are less expencive on most cpu's than taken branches).
Feb 24 2003
parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
The way most cpu's compile if/else is:

if it's just an if clause, it assumes the branch *will* be taken, and puts
the code inline

if it's an if/else clause, it assumes the else is the most likely branch,
but keeps the 'if' portion
inline also which requires a jump-around.

This is so an implementation detail.  Some cpu's can't branch very far so it
pays to keep the code close together in memory.  On some the branch is
expensive if taken, on some it's expensive both ways, on others (older
cpu's) it's no more expensive than any other instruction.

The compiler vendor is the one that should be worrying about how to encode
the semantics of the program into the cpu's instruction set and optimizing
around its performance characteristics.

The only case where I feel something is missing is with SIMD instructions;
there is a basic register type on the machine that we don't have access to
at high level.  Arrays can fill this role, but many SIMD operations involve
rearranging the slots or converting from one bit size to another... things
array operations do not easily represent.  And the SIMD instructions usually
are designed for a specific size array.  Sure you can use any size and
ignore the remainder of the results.

Inline assembler is good for expressing an routine as efficiently as
possible.  It's not good for exposing a low level datatype.

Sorry I seem to have changed the subject... ;)

I agree with the subject line.  Succinctness *is* power.  Explicitness just
adds bloat.  It's useful bloat sometimes, but it can and does get in the
way.  The requirement for being explicit should be in the coding standards
for the company or project, not in the language.  The language should allow
succinctness or explicitness, as the circumstances require.

Sean

"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:b3dgjj$2qiq$1 digitaldaemon.com...
 as do most modern JavaVM's (only the early 1.0.x where pure interpreters)
 Java VM's are not all JIT (compile before) some are dynamic compilers
 (compile if its used more than once as compilation + execute time can be
 longer than interpret once time) also this allows the true main line of

 code to be compiled.
 with C compilers 'if' is usally compiled as branch over the if clause,

 a dynamic compiler if the if cluase is not entered then it is compiled as

 branch out of the main line to the if clause making the common case code
 faster (missed branches are less expencive on most cpu's than taken
 branches).

Feb 24 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Ken Carpenter" <kencr shaw.ca> wrote in message
news:b3cg9g$1tfo$1 digitaldaemon.com...
 "Mark T" <Mark_member pathlink.com> wrote in message
 news:b3aonm$dpc$1 digitaldaemon.com...
 In article <b38jlm$1nb9$1 digitaldaemon.com>, Walter says...
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b37347$cdr$1 digitaldaemon.com...
 http://www.paulgraham.com/fix.html




Their respective VM's are pretty similar in how they work, and similar in being relatively large, although C#'s is much more ambitious.
 Just to clarify, C# and other .NET languages are first compiled to a "VM"
 code (CIL), but they are then compiled to native code before they are
 executed.

Of course. However, the native code is not stored anywhere, so at some point during the execution of your app it is going to spend time compiling. For a large app, this can be a very substantial performance hit. The upside of JITting is the generated code can be customized to the particular CPU being used.
Feb 24 2003
parent "Ken Carpenter" <kencr shaw.ca> writes:
"Walter" <walter digitalmars.com> wrote in message
news:b3f78a$h06$1 digitaldaemon.com...
 Of course. However, the native code is not stored anywhere, so at some

 during the execution of your app it is going to spend time compiling. For

 large app, this can be a very substantial performance hit. The upside of
 JITting is the generated code can be customized to the particular CPU

 used.

Actually, it is possible to "pre-JIT" the code using the ngen utility (Native Image Generator). This can be used to precompile all (or some) of the assemblies used in your application. You might, for example, choose to do this at install time. There is one major caveat, however. The JIT performs on-the-fly code optimizations, while ngen does not. Thus, depending on the type of code in a given .NET assembly the JIT may run slower or faster than the precompiled version. Your profiler is your friend here. Ken Carpenter
Feb 25 2003
prev sibling next sibling parent "Walter" <walter digitalmars.com> writes:
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b37347$cdr$1 digitaldaemon.com...
 http://www.paulgraham.com/power.html

A good read. The major cases where D significantly increases the succintness of programs: 1) garbage collection - all that memory management code is gone. It's amazing how this cleans up and simplifies code. 2) class objects referenced by handles only - gone are the need for and complicated semantics of copy constructors and assignment overloads. 3) array management - the whole scheme of slicing, concatenation, and automatic memory management of arrays is a big shrinker of programs. 4) templates - I believe (though not yet born out by experience) that D's practice of grouping a bunch of related declarations under one template is a big shrinker for template programming.
Feb 22 2003
prev sibling parent xyzzy <xyzzy adventure.com> writes:
On Sat, 22 Feb 2003 05:51:03 +0000 (UTC), Mark Evans 
<Mark_member pathlink.com> wrote:

 A must read from Paul Graham.  I could not have offered a better 
 rationale for
 first-class functions, though the principle stated is general, and so 
 deserves
 its own thread.

A tangental idea comes from Edward De Bono's call for Simplicity. Or put another way, a programming language should be simple but not simplistic, plus that in order to implement something that is simple to use, may very well involve a deal of complexity 'under the hood'. -- xyzzy
Feb 23 2003
prev sibling parent reply Dan Liebgold <Dan_member pathlink.com> writes:
A good description of what first class functions entail from the excellent
"Structure and Interpretation of Computer Programs", by Abelson and Sussmen:


"In general, programming languages impose restrictions on the ways in which
computational elements can be manipulated. Elements with the fewest restrictions
are said to have first-class status. Some of the ``rights and privileges'' of
first-class elements are:64

* They may be named by variables.
* They may be passed as arguments to procedures.
* They may be returned as the results of procedures.
* They may be included in data structures.

Lisp, unlike other common programming languages, awards procedures full
first-class status. This poses challenges for efficient implementation*, but the
resulting gain in expressive power is enormous.

*: The major implementation cost of first-class procedures is that allowing
procedures to be returned as values requires reserving storage for a procedure's
free variables even while the procedure is not executing."


Dan Liebgold
Feb 25 2003
parent Mark Evans <Mark_member pathlink.com> writes:
The Oz book claims that 'procedure' is the more general concept (2.3.4).  So it
talks about first-class procedures, which is a new twist, but basically sound,
though it might ruffle feathers among functional programmers.

http://www.info.ucl.ac.be/people/PVR/book.html

Mark


A good description of what first class functions entail from the excellent
"Structure and Interpretation of Computer Programs", by Abelson and Sussmen:

Feb 26 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Mark Evans" <Mark_member pathlink.com> wrote in message
news:b30vu9$np6$1 digitaldaemon.com...
 That Wellesley CS professor's summary of first-class functions is not

 correct.  (He skirts some issues for the sake of not confusing students.)

 Microsoft's Vault site has a better discussion.  It warns, "The

 between a Vault function and a C function pointer can be rather subtle."

 concept of closure is what counts here.

 http://research.microsoft.com/vault/learn/tutorial/closures.htm

 It is vindication for my point of view that Microsoft should adopt

 functions in its version of "the next systems language" and I hope D does

 same.

One point is the article saying that nested functions "capture" the value of variables in the enclosing environment at the point of declaration of the nested function. This is in contrast to pascal where the nested function directly references the enclosing stack frame.
Feb 20 2003