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