On 18/08/2012, at 6:19 AM, Dobes Vandermeer wrote:
> 
> What are you saying, is that your internal representation makes it difficult 
> or impossible.  However, this isn't the only representation available, so 
> really what you are saying is that you don't want to change your 
> representation.

No, its not the internal representation that is the problem,
its the object model chosen: traditional imperative block
structured programming.

If you want to avoid this problem you can use the functional
constructions such as

        let ?x = expr in 

where you cannot refer to x until after it is initialised. 

Furthermore the problem is made worse by a non-tradiational
lookup model: Felix uses "setwise lookup" which in C is called
"function scope".

This choice eliminates the need for forward declarations.

The fact variables are un-initialised at the object code level
is a design feature of C++. Felix initialises all variables
before they're used with the C++ default constructor.

Certain types have trivial constructors in C++,
such as int, pointers, etc, which don't set any bits.

This is a deliberate choice in C++, for performance reasons.

Felix is C++ underneath. That is a design choice with both
good and bad consequences.

To actually check if a variable is set before use is a very hard
problem in this context: it requires very expensive non-linear
data flow analysis, particularly in the presence of aliasing.

Syntactically, you cannot define a "val" without an initialiser,
and usually it's going to be set before use. Since you cannot
address a val, you don't have to worry about aliasing and
in straight line code its easy to check for "set before use".

Things get more difficult if you have conditional gotos, as I'm 
sure you can imagine, you have to prove there is no control path
which could initialise a val prior to a use before issuing a diagnostic.

In C++ the rule is "you cannot jump past an initialisation".
But C++ has blocks. Felix does not. Felix does have nested functions
which work like blocks when called but they're not quite the same,
because you cannot "return" from the main function from inside
the nested one. Nor can you yield. You can jump out though.

To implement blocks, I have to flatten them, and probably implement
non-local return (and yield).

The problem here is C, it lets you "return" from inside a block.
This is bad structure (a block is really a procedure with no arguments).


> I guess performance isn't THAT important to me.

Oh yes it is, it is the ENTIRE reason for using computers!
They're there to automate what humans could already do with
many people, organisation, and lots of labour.

The Sydney Harbour Bridge required solution of 103 simultaneous
equations. That requires inverting an 103 square matrix, roughly
an N^3 operation. It was done by teams of engineers with slide
rules and the calculation took MONTHS to complete.

The original version of Felix used the C++ class object exclusively,
without optimisation. For a short Ackermann calculation Felix can now
do in a few seconds, this blew the memory on a PC and managed to
complete on a bigger Power Mac in 16 hours.

Performance matters. The whole of mathematics is about optimisation.
What else do you think a theorem is but an optimisation?

>  There's this idea that programmer time is more important than program 
> runtime, so one should avoid things that confuse the programmer.  If the 
> runtime behavior depends heavily on optimizer decisions, that's confusing and 
> can lead to hard to find bugs.

Of course. I do not disagree with your concerns. But the solution requires some 
thought.
We have to keep performance, in fact we need to improve it.
There's sometimes a price. The trick is to find a nice way to get good 
performance
without code being too hard to reason about.

The idea of "const" was just that: the compiler can be ultra-agressive with code
motion. But actually not as aggressive as you might like due to the problem
that even const functions are not perfect:

        perfect = const + total
        const = pure fun (no dep vars, dep params only)
        fun = no-side-effect
        
That's rough guide, its more complicated because of pointers
(deref pointers = dep on a var)

> I think it's important that programmers can understand easily how their code 
> will behave BEFORE they run it.

Sure.

> Lexical ordering seems relatively simple to me, maybe I'm missing something:

Felix doesn't use lexical ordering for lookup. So the check has to be done
after lookup.

Define before use does not support recursion.

> I don't have a problem with that syntax but I think val is supposed to do 
> that job.

It was, but it turns out it doesn't.

> I guess what you are referring to is that if you divide by zero the program 
> may crash or throw an exception.

What I'm saying is that if you write:

        if divisor == 0 then 1 else dividend / divisor endif

does not crash **because** the second and third arguments are lazily
evaluated. In C:

        divisor == 0 ? 1 : dividend / divisor

You cannot write this function as a function because it is lazily evaluated in 
C,
and function arguments are eagerly evaluated. 

There is a wide class of functions where it makes no difference if the arguments
are eagerly or lazily evaluated, and "val" supports that. Nice functions
like "sin" just don't care.

--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to