Re: Seeking computer-programming job (Sunnyvale, CA)

S

Series Expansion

Luckily your doubt does not determine reality.

Of course not; it merely reflects it.
All I'm saying is that Robert could find a way to learn these skills even if
he is rather tight for money.  I know poor people who have enough computer to
learn client/server apps and Java EE "stuff", should that be their bent, even
though they receive public assistance and have rather low-paying jobs.

The hypothetical case was someone that was almost totally destitute,
with essentially no disposable income remaining after paying for
shelter, food, other basic consumables (e.g. toothpaste), and basic
utilities.

Someone with a bit of additional money above that can save up for a
computer. Someone with at least $50/mo above that can get their own do-
most-things-with-it broadband and not just leech off a web-only
connection in a cyber-cafe or whatever.
 
P

Pascal J. Bourguignon

Seamus MacRae said:
Au contraire. They check everything else for consistency at compile
time too. The code that puts things in the list. The code that takes
things out. The code that runs them.

The information that "the things in the list should be runnable" has
to be expressed in the program somehow. In a dynamically-typed
implementation, it would be implicit in the code -- unless the code
had bugs, and then the intent would not be clear. Was it an error that
a non-runnable went into the list, or was it an error that something
else assumed everything taken out of the list was runnable, or was
something else wrong entirely?

The intent could be made clear by adding comments, but now the same
information is in two places: in the code and in comments, and they
can get out of synch.

Or you can use static type checking. Then the types in the code
document the intent, and the things that have to be consistent (the
information about intent, and the actual objects put in the list and
actions performed on the items taken out) are checked for consistency
automatically by the computer to boot. They can't get out of
synch. And if there's an error, the intent is clear. If a List<Object>
item is assumed Runnable assuming they're runnable is the error. If a
non-Runnable is put in a List<Runnable> putting in a non-runnable is
the error.

Problem solved.

There's a easier and more powerful way to solve that kind of problem.
It is to write a DSL (ie. macros) in Lisp, to generate correct code in
the first place.

Of course, you will object how to be sure the macros are correct?
I'll object how to be sure your type expressions are correct?

And unless your type system is Turing Complete, there are necessarily
specifications you cannot write.

And when your type system is Turing Complete, there are necessarily
bugs written in it, and a lot of time spend on it, because of the
syntactic complexity (eg. C++ templates!).


Lisp macros are just a much simplier and much more powerful to archive
the same results much faster.
 
T

thomas.mertes

I admit having no clue about Seed7 templates. If they are like C++
templates then I have to say no, I will definetly not expose myself to
that kind of pain again. I do know better solutions: Common Lisp.

I see C++ templates also as ugly kludge. Seed7 templates are just
functions which are executed at compile time. This functions can
use types as parameters or result and usually have declaration
statements in the body. Normal functions are called explicit
therefore Seed7 template functions are also called explicit.

const proc: DEFINE_MAX (in type: aType is func
begin

const func aType: max (in aType: val1, in aType: val2) is func
result
var aType: result is aType.value;
begin
if val1 > val2 then
result := val1;
else
result := val2;
end if;
end func;

end func;

Instatiation is done with

DEFINE_MAX(integer);
DEFINE_MAX(myType);

Afterwards max(number, 3) is available. Another example where a
template defines a statement can be found here:

http://seed7.sourceforge.net/examples/for_decl.htm

BTW: In many languages the concept of an array is hardcoded in the
compiler. In Seed7 arrays are implemented as template. The array
template is defined in a library.

[snip]
Ah, I do smell a business here. What would be daily rates for the help?

In virtual money you can pay big rates. :) Additionally I can offer
a place in the (soon to be created) hall of fame.

[snip]
Ooookaaaayyy - so I did as you told me. Results:

frgo@ccde007 ~/Downloads/seed7/src
$ make -f mk_osx.mak clean
rm *.o *.a depend a_depend b_depend c_depend version.h
rm: *.o: No such file or directory
rm: *.a: No such file or directory
rm: depend: No such file or directory
rm: a_depend: No such file or directory
rm: b_depend: No such file or directory
rm: c_depend: No such file or directory
rm: version.h: No such file or directory
make: *** [clean] Error 1

Hm. Okay. Some suggestions for changes:

1. In the makefile, change this:
clean:
rm *.o *.a depend a_depend b_depend c_depend version.h

into:

RM = rm -f

clean:
$(RM) *.o *.a depend a_depend b_depend c_depend version.h

Good idea.
2. Use a simple script to detect on which platform you are. Then select
the appropriate makefile and execute. No README to be maintained, no
nothing, even better user experience.

I started with a script for Windows (yes a *.bat file). Under
Windows several compilers and make utilitys need support. I am
not finished with the script and it would also need input
from the user. "Do you want to use MSVC or Mingw with gmake,
nmake or make?".

For an unix like OS such a script would be easier.

[snip]
Confirmed. Took about 30 seconds total.

HI INTERPRETER Version 4.5.4741 Copyright (c) 1990-2009 Thomas Mertes
262 /Users/frgo/Downloads/seed7/lib/syntax.s7i
3518 /Users/frgo/Downloads/seed7/lib/seed7_05.s7i
32 level.sd7
3812 lines total
254133 lines per second
1699814 bytes
Current level is 4741

Great. To check the functionality the following program can
be used.

cd /Users/frgo/Downloads/seed7/prg
./hi chk_all

When all goes well you can do

./hi panic

and tell me how many monsters you have killed.
Knew that. Ah - we don't need a GMP to do unlimited precision integers
in Common Lisp. It's in the ANSI Standard - yada yada, sorry, couldn't
resist. :)

Seed7 doesn't need GMP either. The build-in bigInteger support
works without GMP. Using the GMP instead of the built-in bigInteger
support is just an option. In the Seed7 programs you don't see any
difference.
No more questions open. I just delivered answers:
Yes, you could ease the build process.
Yes, it compiles and runs on OS X.
Yes, it runs ok on OS X.

Thank you for the information.
Hope to meet you eventually (in the English meaning, not the false German
"translation" ;-). I'll be not be in Ennepetal though for some
time.

I found Ennepetal with Google. Now I have to reason about the
meaning of 'meet' in different languages. :)

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
 
P

Pascal J. Bourguignon

eric-and-jane-smith said:
(e-mail address removed) (Pascal J. Bourguignon) wrote in



It's hard to make the power of CL macros clear to non-Lispers. They think
in terms of the macros of other programming languages, and have no idea
what CL macros are. From their point of view, we seem to be telling them
we want to use macros as a klugey substitute for C++ templates, or for the
Java type system, or whatever.

This kind of debate tends to go in circles till it degenerates, because the
parties aren't really communicating, because the same words mean different
things to them.

Ok, then let me summarize lisp macros as being hooks in the lisp compiler.


Imagine what you could do if you could modify your compiler on the fly:

- you could change your programming language, to specialize it for
your current problem,

- you could implement more sophisticated type or semantic checking,

- you could implement higher level code generation strategies
(eg. instead of just generating machine code from arithmetic
operations or message sending, you could generate programs from a
declarative description of your problem),

- etc.
 
F

Frank GOENNINGER

Great. To check the functionality the following program can
be used.

cd /Users/frgo/Downloads/seed7/prg
./hi chk_all

Results:

frgo@ccde007 ~/Downloads/seed7/prg
$ ../src/hi chk_all
HI INTERPRETER Version 4.5.4741 Copyright (c) 1990-2009 Thomas Mertes
262 /Users/frgo/Downloads/seed7/lib/syntax.s7i
3518 /Users/frgo/Downloads/seed7/lib/seed7_05.s7i
70 /Users/frgo/Downloads/seed7/lib/shell.s7i
227 chk_all.sd7
4077 lines total
239823 lines per second
1755426 bytes
compiling the compilerhi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkinthi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkstrhi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkprchi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkbighi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkboolhi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chksethi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkexchi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay

Is it now ok or is there an error ?!?!?
When all goes well you can do

./hi panic

and tell me how many monsters you have killed.

Daredevil that I am I decided to have it a go. Pacman in a
terminal. Nice game, so 20th century.

2 monsters only, though ;-)

Cheers
Frank
 
A

anonymous.c.lisper

Ok, then let me summarize lisp macros as being hooks in the lisp compiler..

Imagine what you could do if you could modify your compiler on the fly:

- you could change your programming language, to specialize it for
  your current problem,

- you could implement more sophisticated type or semantic checking,

- you could implement higher level code generation strategies
  (eg. instead of just generating machine code from arithmetic
  operations or message sending, you could generate programs from a
  declarative description of your problem),

- etc.

Not only can you modify your compiler on the fly,
you can generate code and modify your program on the fly.

There are certain languages where you *can* do that,
but I doubt that they make that sort of functionality *easy*.
 
P

Pascal J. Bourguignon

eric-and-jane-smith said:
(e-mail address removed) (Pascal J. Bourguignon) wrote in



A lot of people might still not get it, even after understanding some of
the kinds of things that can be done with them. They might have bad
memories of trying to use the macros of other programming languages, and
making a big mess with them, such that their programs gradually became
hard to read and maintain. Their attitude might be that the more you can
do with them, the bigger a mess you can make with them.

Macros in other programming languages often seem to obfuscate the code as
much as they improve it, such that there may be little or no net gain.
But CL macros can make the code orders of magnitude clearer, easier to
read, easier to work with, and less error prone. There is a powerful
synergy between the different advantages of CL macros, such that knowing
them as a list of advantages is not enough to understand their real
power.

People with a lot of experience in a lot of other programming languages
are likely to think the concept of macros is simple and universal. Their
experience tells them they're like a two-edge sword, to be careful with,
and to not expect miracles from. The idea that in CL it would not be
unusual to write most of a 20-line function as one big macro call, with
other macro calls nested in that one, is likely to seem bizarre to them,
and give them even more reason to avoid CL.

And that's just one of many reasons why it's hard to advocate for CL to
people who have little or no experience with it. No matter what we say,
we sound like raving maniacs, till they find out for themselves, by
getting real experience with CL, and not just testing the waters by
writing some simple code that only uses a small fraction of the features
of the language.

Well at that point I can only say that, well over here we're not (all)
raving maniacs, that we have useful tools that help solve or obviate a
lot of problems found with other programming languages, and point to
that tutorial: http://www.lisperati.com/casting.html

(and http://www.cliki.net/Online Tutorial for those who want to
learn more).
 
T

thomas.mertes

Results:

frgo@ccde007 ~/Downloads/seed7/prg
$ ../src/hi chk_all
HI INTERPRETER Version 4.5.4741 Copyright (c) 1990-2009 Thomas Mertes
262 /Users/frgo/Downloads/seed7/lib/syntax.s7i
3518 /Users/frgo/Downloads/seed7/lib/seed7_05.s7i
70 /Users/frgo/Downloads/seed7/lib/shell.s7i
227 chk_all.sd7
4077 lines total
239823 lines per second
1755426 bytes
compiling the compilerhi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkinthi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
....

hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay

Is it now ok or is there an error ?!?!?

Good question. On other Windows/Linux/Unix computers there are no
such errors. Naturally I cannot exclude the possibility that the
errors are caused by the hi interpreter or the Seed7 library. The hi
interpreter and the Seed7 runtime library always check the return of
malloc (for != NULL). When malloc is not able to allocate memory an
exception or an error message followed by exit(), should happen.
Since the error messages above do not come from the hi interpreter
or the Seed7 runtime library they are probably generated by the Mac
OS libc. The malloc issues this errors but is probably capable to
return memory afterwards. Otherwise some Seed7 messages would have
shown up.

Googling shows that others also get this errors:

http://www.macosxhints.ch/forums/showthread.php?t=12392
http://bugs.python.org/issue2901
http://lists.macosforge.org/pipermail/macports-users/2008-April/009915.html
http://trac.macports.org/ticket/18073
http://discussions.apple.com/thread.jspa?messageID=9128509
http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=13499

All these seem to be related to Mac OS. Maybe running a check
(E.g.: chkint.sd7) alone (without being called from chk_all.sd7)
would give more information:

./hi chkint
./hi comp chkint
./chkint

This three lines start the check program for integers with the
interpreter, compile the check program and start the executable
of it. When './hi chkint' has the same output as './chkint' then
this is a hint that the malloc error messages are just to be
considered as warnings internal to the malloc function. In this
case shutting the errors would help (I don't know how to do this).
Daredevil that I am I decided to have it a go. Pacman in a
terminal. Nice game, so 20th century.

2 monsters only, though ;-)

You need more practice.
Did you succeed landing on the moon?

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
 
T

thomas.mertes

Results:

frgo@ccde007 ~/Downloads/seed7/prg
$ ../src/hi chk_all
HI INTERPRETER Version 4.5.4741 Copyright (c) 1990-2009 Thomas Mertes
262 /Users/frgo/Downloads/seed7/lib/syntax.s7i
3518 /Users/frgo/Downloads/seed7/lib/seed7_05.s7i
70 /Users/frgo/Downloads/seed7/lib/shell.s7i
227 chk_all.sd7
4077 lines total
239823 lines per second
1755426 bytes
compiling the compilerhi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay
chkinthi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
....

hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
hi(3598) malloc: *** mmap(size=4000002048) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
- okay

Is it now ok or is there an error ?!?!?

Good question. On other Windows/Linux/Unix computers there are no
such errors. Naturally I cannot exclude the possibility that the
errors are caused by the hi interpreter or the Seed7 library. The hi
interpreter and the Seed7 runtime library always check the return of
malloc (for != NULL). When malloc is not able to allocate memory an
exception or an error message followed by exit(), should happen.
Since the error messages above do not come from the hi interpreter
or the Seed7 runtime library they are probably generated by the Mac
OS libc. The malloc issues this errors but is probably capable to
return memory afterwards. Otherwise some Seed7 messages would have
shown up.

Googling shows that others also get this errors:

http://www.macosxhints.ch/forums/showthread.php?t=12392
http://bugs.python.org/issue2901
http://lists.macosforge.org/pipermail/macports-users/2008-April/009915.html
http://trac.macports.org/ticket/18073
http://discussions.apple.com/thread.jspa?messageID=9128509
http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=13499

All these seem to be related to Mac OS. Maybe running a check
(E.g.: chkint.sd7) alone (without being called from chk_all.sd7)
would give more information:

./hi chkint
./hi comp chkint
./chkint

This three lines start the check program for integers with the
interpreter, compile the check program and start the executable
of it. When './hi chkint' has the same output as './chkint' then
this is a hint that the malloc error messages are just to be
considered as warnings internal to the malloc function. In this
case shutting the errors would help (I don't know how to do this).
Daredevil that I am I decided to have it a go. Pacman in a
terminal. Nice game, so 20th century.

2 monsters only, though ;-)

You need more practice.
Did you succeed landing on the moon?

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
 
P

Pillsy

On 13 Mai, 10:52, Nicolas Neuss <[email protected]>
wrote: [...]
Hmm, I consider myself a Lisp fan and would not want to choose between
these two statements.  Maybe you should refine your simplistic world
view a little qbit?
As I already said: This is not my simplisic world view.
Proof: Just tell me about great language features that are
missing in Lisp.

This is a really strange request, because language features aren't
arbitrarily composable. In a lot of circumstances adding one feature
means you've got to get rid of, or compromise, another feature. C-
style pointers strike me as the best example of this kind of feature;
they're a great feature for C to have, but you don't want them in a
lot of other languages because the make it so easy for you to light
your own hair on fire[1]. Common Lisp relegates them to the realm of
non-standard extensions, which is (IMO) as it should be.

There are any number of other features like that. Ease of
implementation is another feature that can be tremendously valuable,
and is one that Common Lisp doesn't pay a whole lot of attention to.

Cheers, Pillsy

[1] Or, in the case of Fortran, because it makes some important
optimizations impossible.
 
S

Stefan Ram

Well at that point I can only say that, well over here we're not (all)
raving maniacs, that we have useful tools that help solve or obviate a
lot of problems found with other programming languages, and point to
that tutorial: http://www.lisperati.com/casting.html

Assume for a moment I had advanced macro capabilities in Java.
I'd write:

public static String getMultiValue( Object valueObject )
{ String result = null;
if( valueObject == null )result = null;

else if( StringValue stringValue =? valueObject )
result = getStringValue( stringValue );

else if( SprayValue sprayValue =? valueObject )
result = getSetValue( setValue );

return result; }

The macro here is marked by the occurence of »=?«, which is
not a regular Java operator, but part of my hypothetical macro
call pattern.

The problem here is readability:

Can others know, what »=?« means in my macro package?
Can they know how to immediately find its documentation?

If I invent and use this macro now, will even I myself
remember its meaning a year later?

The same coded in Java without macros /is/ more verbose,
but also more readable to someone who knows Java:

public static String getMultiValue( Object valueObject )
{ String result = null;
if( valueObject == null )result = null;

else if( valueObject instanceof StringValue )
{ StringValue stringValue =( StringValue )valueObject;
result = getStringValue( stringValue ); }

else if( valueObject instanceof SprayValue )
{ SprayValue setValue =( SprayValue )valueObject;
result = getSetValue( setValue ); }

return result; }
 
T

Tamas K Papp

The macro here is marked by the occurence of »=?«, which is not a
regular Java operator, but part of my hypothetical macro call pattern.

The problem here is readability:

Can others know, what »=?« means in my macro package? Can they know
how to immediately find its documentation?

Yes, of course. You should name your macro informatively (CL
programmers usually do), and with a decent IDE, you should have no
problem accessing documentation with a few keystrokes.
If I invent and use this macro now, will even I myself remember its
meaning a year later?

You could say the same about functions. Then you should not use them,
because who knows if you will remember what they do in a year :)

Generally, this is not a problem.
The same coded in Java without macros /is/ more verbose, but also more
readable to someone who knows Java:

Macros provide abstraction: the idea is that you do not have to parse
the code mentally if you know what it _does_. Abstraction makes code
more readable.

It is very strange how some programmers resist the abstraction
provided by macros. I would be surprised if a mathematician argued
that one should not prove new theorems, because it is hard to remember
what they show a year later. Yet I see this attitude with non-Lisp
programmers. Weird.

Tamas
 
T

Tamas K Papp

And that's just one of many reasons why it's hard to advocate for CL to
people who have little or no experience with it. No matter what we say,
we sound like raving maniacs, till they find out for themselves, by
getting real experience with CL, and not just testing the waters by
writing some simple code that only uses a small fraction of the features
of the language.

I prefer not to advocate. I am happy to discuss CL with people, but I
would be reluctant proselytize vehemently.

It took me about a year to "get" macros even partially, and I am sure
there is still so much more to learn. The problem is that it is hard
to demonstrate the most useful features in short code snippets that
non-lispers could be expected to understand.

Also, macros can be abused. I have done that when I was learning
Lisp, and only learned how to write better macros gradually with the
guidance of the kind people on c.l.l. I can imagine that in a
corporate environment with many programmers, one would be wary of
inexperienced programmers writing macros, especially if you don't have
the time or inclination to teach them better because of high personnel
turnover rates.

Tamas
 
L

Lew

Stefan said:
  The same coded in Java without macros /is/ more verbose,
  but also more readable to someone who knows Java:

public static String getMultiValue( Object valueObject )
{ String result = null;
  if( valueObject == null )result = null;

  else if( valueObject instanceof StringValue )
  { StringValue stringValue =( StringValue )valueObject;
    result = getStringValue( stringValue ); }

  else if( valueObject instanceof SprayValue )
  { SprayValue setValue =( SprayValue )valueObject;
    result = getSetValue( setValue ); }

  return result; }

An experienced Java programmer will see this series of 'instanceof'
operators and look for a way to code the thing polymorphically.

interface Multi<T>
{
public String getValue( T arg );
}
class StringVersion implements Multi<String>
{
public String getValue( String arg )
{
return getStringValue( arg );
}
}
class SprayVersion implements Multi<Spray>
{
public String getValue( Spray arg )
{
return getSprayValue( arg );
}
}

etc.
 
G

gugamilare

Yes, of course.  You should name your macro informatively (CL
programmers usually do), and with a decent IDE, you should have no
problem accessing documentation with a few keystrokes.


You could say the same about functions.  Then you should not use them,
because who knows if you will remember what they do in a year :)

Generally, this is not a problem.


Macros provide abstraction: the idea is that you do not have to parse
the code mentally if you know what it _does_.  Abstraction makes code
more readable.

It is very strange how some programmers resist the abstraction
provided by macros.  I would be surprised if a mathematician argued
that one should not prove new theorems, because it is hard to remember
what they show a year later.  Yet I see this attitude with non-Lisp
programmers.  Weird.

Tamas

I agree with you. As a mathematician, I believe that CL macros are to
programming as abstractions are to mathematics. For instance,
mathematical induction is a kind of abstraction (a very simple and
useful one). This means that languages like Java can't be used to
"prove anything by induction" ;-) it must do everything from bare
metal (just like formal mathematics, and by formal mathematics I mean
http://us.metamath.org/mpegif/zorn2.html ).
 
T

thomas.mertes

[snip]

I don't know why my message was transmitted two times, but I have an
idea how the error messages occur:

The test program (chk_all.sd7) starts other programs one by one. It
does this with popen(). The system function popen() opens a pipe and
the result of the command execution can be read from this pipe. To
read (hopefully) the whole pipe into a string the function 'gets'
is called with the request to read 999999999 characters. The Seed7
function 'gets' is implemented with the C function filGets()
(in file_rtl.c). The function filGets() is really low level (other
interpreters/librarys probably also have similar functions) and
uses several strategies to do its job. In order to work reasonable
good in the common case (reading just some characters) memory for
the requied maximum length is requested with malloc(). After the
data is read the result string is shrinked to the actual size (with
realloc). When the memory cannot be requested a different strategy
is used. In this case the function trys to find out the number of
available characters (which is possible for a regular file but not
for a pipe). If this fails also a third strategy is used. A smaller
block is requested, this block is filled with data and resized in a
loop. So it is nothing special when a malloc fails in the filGets()
function. There are alternative code paths to provide the requested
functionality.

The point is that the Mac OS malloc() complains when it is not
capable to do its job. This is not according to the specification
of malloc(). According to all definitions of malloc it should just
return NULL when it cannot allocate the requested amount of memory.
Did I mention that other operating systems did not have the
slightest problems when I tell them to malloc huge amounts of
memory. Either they deliver it or they return NULL. No performance
problem or error message.

One solution would be: Find out a way to tell Mac OS malloc()
that it should behave according to the specification (stop
complaining). Maybe there is a compiler flag, a #define a callback
function or something else. When this is not possible a work
around is necessary.

To code around this bug of Mac OS it is necessary to find out
the maximum blocksize that can be requested with malloc without
complains. Then the function filGets() could use this limit to
avoid strategy 1 and switch to strategy 2 and 3 immediate.

Hopefully I can add some fix to the next release.

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Seed7 - The extensible programming language: User defined statements
and operators, abstract data types, templates without special
syntax, OO with interfaces and multiple dispatch, statically typed,
interpreted or compiled, portable, runs under linux/unix/windows.
 
G

gugamilare

  Assume for a moment I had advanced macro capabilities in Java.
  I'd write:

public static String getMultiValue( Object valueObject )
{ String result = null;
  if( valueObject == null )result = null;

  else if( StringValue stringValue =? valueObject )
  result = getStringValue( stringValue );

  else if( SprayValue sprayValue =? valueObject )
  result = getSetValue( setValue );

  return result; }

  The macro here is marked by the occurence of »=?«, which is
  not a regular Java operator, but part of my hypothetical macro
  call pattern.

  The problem here is readability:

  Can others know, what »=?« means in my macro package?
  Can they know how to immediately find its documentation?
May I say that your macro is very lame and useless? Here is a good
example of what a good macro can do. CL doesn't have a way to
serialize functions to a file. This library (I wrote it)

http://github.com/gugamilare/storable-functions/

makes this possible. It does not rely on any internal representation
of the functions by some implementation - this would make the code
unportable - but it provides a macro that retrieves the function's
body to be stored into a file and then restored back again. It is as
simple as this: instead of writing (lambda (...) ...) you write (st
(lambda (...) ...).

In Java I am pretty sure this isn't conceivable because

1) Java does not have dynamically created functions (or am I wrong?)
2) Java Code is not an easy manipulable data
3) Java doesn't have macros.

As you can see, macros not only provide a way to make your
applications shorter or more readable, but they also make it possible
to do somethings that otherwise couldn't be done.
 
P

Pascal J. Bourguignon

Assume for a moment I had advanced macro capabilities in Java.
I'd write:

public static String getMultiValue( Object valueObject )
{ String result = null;
if( valueObject == null )result = null;

else if( StringValue stringValue =? valueObject )
result = getStringValue( stringValue );

else if( SprayValue sprayValue =? valueObject )
result = getSetValue( setValue );

return result; }

The macro here is marked by the occurence of »=?«, which is
not a regular Java operator, but part of my hypothetical macro
call pattern.

The problem here is readability:

Can others know, what »=?« means in my macro package?
Can they know how to immediately find its documentation?

If I invent and use this macro now, will even I myself
remember its meaning a year later?


These are valid questions.

Happily they have been solved by Lisp programmers, perhaps even before
you were born.


To help knowing what =? means, lisp programmers tend to avoid using
punctuation character in their operator names. They rather use
english words (separated by dashes). For example, they would have
used 'equivalent' instead of '=?'.

Do you think Java programmers would be able to use this advanced
technology? The reference manuals you need to consult to use it are
rather thick. Cf. http://www.merriam-webster.com/

More over, to help knowing what arguments a new operator such as
'equivalent' may take, they use another technological advancement :
the parentheses. Stand with me, it's rather complicated. They use
two (*TWO* !) special characters, named 'open parenthesis' and 'close
parenthesis' that look like: '(' and ')'. The trick here is that
they put all the arguments used by the new operators 'inside' the
parentheses. This means that they write: the open parenthesis '(',
the operator (eg. 'equivalent'), and the arguments separated by
spaces, and finally the close parenthesis ')'. This may sound
complicated as explained here, but it's rather simple:

(equivalent stringValue valueObject)

So there you can see clearly that the operator is meant to indicate
whether the _two_ arguments (in this case) stringValue and valueObject
are equivalent.

Notice that if you have a keyboard of the most recent generation you
may be lucky to be able to enter them directly with a special movement
of the fingers: first press one of the two "shift" keys, keep one
finger on the shift key pressed, and then type either 9 or 0. You
should get an open parenthesis for 9, and a close parenthesis for 0.



You may laugh at my explications here, but this is really quite
advanced a technology. They are a lot of happy consequences from the
use of these "parentheses". To answer your second question, one of
the consequences is that parsing lisp expressions is trivial; the
grammar is:

expression ::= atom | '(' { expression } ')' .

Yes, only one non-terminal, only one terminal (plus the two
parentheses), and only one grammar rule. It's can hardly be simplier.
So this grammar can easily be implemented in any tool such as in
editors. And therefore editors can easily provide support for
syntactic editing. Since the operator is always placed in the first
position of a form (a code expression), the editors can easily find
it, and then call up the documentation about the operator.



And finally, using these two advanced technologies, your third
question becomes irrelevant. One year later, you won't need to
remember what it is, you will just read the expression and be able to
understand what it does without even needing to check the source of
the macro.


But notice that if you have some doubt, you may:

- ask the editor to show you the documentation.

- ask the editor to show you the source.

- ask the lisp system to expand the macro call, so you can see the
code that's generated, and if you can understand it, you will
understand the meaning of the macro.

The same coded in Java without macros /is/ more verbose,
but also more readable to someone who knows Java:

public static String getMultiValue( Object valueObject )
{ String result = null;
if( valueObject == null )result = null;

else if( valueObject instanceof StringValue )
{ StringValue stringValue =( StringValue )valueObject;
result = getStringValue( stringValue ); }

else if( valueObject instanceof SprayValue )
{ SprayValue setValue =( SprayValue )valueObject;
result = getSetValue( setValue ); }

return result; }

Why do you stop there? Why don't you read the JVM byte code to
understand the method? It would be more readable and more
understandable, wouldn't it?
 
P

Pascal J. Bourguignon

Tamas K Papp said:
I prefer not to advocate. I am happy to discuss CL with people, but I
would be reluctant proselytize vehemently.

It took me about a year to "get" macros even partially, and I am sure
there is still so much more to learn. The problem is that it is hard
to demonstrate the most useful features in short code snippets that
non-lispers could be expected to understand.

Also, macros can be abused. I have done that when I was learning
Lisp, and only learned how to write better macros gradually with the
guidance of the kind people on c.l.l. I can imagine that in a
corporate environment with many programmers, one would be wary of
inexperienced programmers writing macros, especially if you don't have
the time or inclination to teach them better because of high personnel
turnover rates.

This argument is wrong.

In the corporate context, with any programming language there are
restrictions. There's a "style guide", sometimes it's even quite thick.

When you use programming language such as C++ there is a lot of things
you are prohibited to use, or that you must do in a given way.

Well it would be the same when using lisp. The inexperienced
programmers would be forbidden to write macros (or would get special
attention in code reviews). But experienced programmers could write
them and provide a DSL library for the inexperienced ones.
 
T

Thomas A. Russ

eric-and-jane-smith said:
Macros in other programming languages often seem to obfuscate the code as
much as they improve it, such that there may be little or no net gain.
But CL macros can make the code orders of magnitude clearer, easier to
read, easier to work with, and less error prone. There is a powerful
synergy between the different advantages of CL macros, such that knowing
them as a list of advantages is not enough to understand their real
power.

Yes, a good point.

I've lately decided that I really like the example of WITH-OPEN-FILE as
an example of a nice Lisp macro. OK, it's already in the language, but
the important point is that it would be something easy to add if it
WASN'T in the language. This exposition can proceed by looking at the
problem it was put in to solve, and comparing it to two Java solutions.

Problem: When you open a file, you have to remember to close it, even if
the code using the file happens to throw an exception.

OK. The standard Java solution would be to use "try ... finally":

OutputStream out = null; // Needs definition outside try block.
try {
out = new FileOutputStream(filename);
// do stuff
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
// Do something like log this.
}
}
}

So, this is just a bit cumbersome, because you have to remember to
declare the variables in the correct place, remember to put in the
finally block, with appropriate safety checks. Note that because the
close() method can also throw an exception, you have to wrap it in its
own exception handling block. That's a lot of infrastructure that you
need to write around the file handling code that you really care about,
namely the "// do stuff" part.

Note in particular, that STATIC TYPING DOES NOTHING to enforce this type
of good programming practice. That's because it isn't a type error, but
an oversight in program strucure. Macros, on the other hand, allow you
to easily capture such good practice.

[Aside: There has of late been a lot of "excitement" about pattern-based
design. This is all well and good, but it is something that,
essentially, Common Lisp has had all along through the judicious use of
macros. In fact, lisp has gone beyond the notion of mere patterns and
instead calls this aspect the process of building a Domain Specific
Language (DSL)]

Now, you can, in fact, write the same thing in Common Lisp, yielding a
program that looks kind of like this:

(let ((out nil))
(unwind-protect
(progn
(setq out (open filename :direction :eek:utput))
;; Do stuff
)
(unless (null out)
(close out))))

where we set up the same basic structure. Now, since we nearly always
want to do something like this when we open the file, we would like to
have a safe way to do this that is convenient and gets the details
right. So we take the basic outline of what we want and write a macro
that embodies this particular idiom:

(defmacro with-open-file ((var filename &rest open-options) &body body)
`(let ((,var nil))
(unwind-protect
(progn
(setq ,var (open ,filename ,@open-options))
,@body)
(unless (null ,var)
(close ,var)))))

So now we have a macro that automatically handles the task of opening a
file and remembering to close it. That simplifies our code to the more
perspicacious and correct, because the macro has been carefully
constructed:

(with-open-file (out filename :direction :eek:utput)
;; do-stuff
)

This also allows us to concentrate our attention on the actual DO-STUFF
part, which is the variable part of this endeavor and the place where
logic bugs can occur. We don't have to bother ourselves looking at all
of the boilerplate and making sure we got it right, since we've already
gotten the boilerplate parts correct in our macro.

So, how would one go about doing something similar in Java. The real
crux of the matter is that there isn't any facility in the language that
allows you to introduce a new control structure that allows you to
insert your actual program into the middle of some combination of
existing constructs.

As near as I can tell, the method one would need to use involves
encapsulating the program you want to execute inside a (possibly
anonymous) class with a defined "run" interface so that it can be
executed. That would involve something along the lines of

public interface FileProcessor {
public void processFile (OutputStream out);
}

public class ProcessFile {
public static void processOpenFile (String filename, FileProcessor worker) {
OutputStream out = null;
try {
out = new FileOutputStream(filename);
worker.processFile(out);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}

OK. With this infrastructure defined, we can now write code that looks
sort of like this:

ProcessFile.processOpenFile(filename,
new FileProcessor () {
public void processFile(OutputStream out) {
// do stuff
}
});

where we create a new anonymous class instance to encapsulate the body
of the code that we want to execute.

So, it is possible to build up such abstractions in Java, but to my eyes
that looks a lot clunkier and less integrated than the Lisp macro
solution. You see, there isn't any way of introducing new forms into
Java that look like the language itself. So there isn't any way to add
your own control structure construct that looks like

with_open_file (out, filename) {
// do stuff
}

which would be the real equivalent of the Common Lisp macro solution.

So this is a very simple example of what is meant when lisp programmers
talk about using macros to write code that is correct, and a very
simplistic example of how we go about writing DSLs to solve problems, by
removing the superstructure required by the programming language from
sight so we can concentrate on getting the actual business logic right.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,796
Messages
2,569,645
Members
45,371
Latest member
TroyHursey

Latest Threads

Top