August 17, 2001 Re: D vs. LX - Typedefs | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 19/ Real typedefs While having 'handle' being separate is sometimes useful, it is also sometimes an impediment (unless you also have conversion rules from a typedef to the typedefed type, and implicit conversion headaches rear their ugly heads). So for LX, I decided to make the creation of a new type not the default, but an option. type coordinate is real coordinate C := 1.0 -- OK function F(real R) return real function F(coordinate C) return coordinate -- Error type distance is other real type time is other real type speed is other real function Div(distance D; time T) return speed written D/T -- OK LATER NOTE: I just discovered you have typealias. OK, let me suggest that typedef should behave the C way (as typealias does today), and that typenew implements the new behavior...?. Don't change the meaning of typedef gratuitously... PS: does your syntax allow: "int typedef handle" as in C? Christophe |
August 17, 2001 Re: D vs. LX - Arrays | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 20/ Arrays and Strings Arrays in LX are constructed generic types, not primitive types. So they don't suffer of any of the problems you mention. I believe this solution is more elegant. Also note that the LX syntax for declaring arrays (determined by a written form on the generic type) doesn't suffer the issues you mention on the C syntax, although there current left to right associativity for named operators requires clumsy parentheses in some cases: array A[1..5] of (pointer to integer) As a reminder, the type is declared with some generic declaration like: generic [range index; type item] type array written array[index] of item In declarations, only the first word appears on the left of the declared name, thus a declaration of an array would use: array A[1..5] of integer Naturally, if you want zero-based arrays with a C-like notation, fine by me: generic [integer size; type item] type carray written item[size] integer X[5] Note that this would cause trouble in the long-term, because the [] notation if not overloaded is for template arguments. Without the declaration above, integer X[5] would be instantiating generic type integer with argument 5. And since integer in LX is actually a generic type, this should be valid... There is no relationship between pointers and arrays in LX (except that both are constructed types). The same should hold for strings as for arrays. They should be constructed, not primitive types. Did I already mention this? Built-in types are EVIL. Christophe |
August 17, 2001 Re: D vs. LX - Synchronized and tasking | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 21/ Synchronize I am afraid that your approach to multitasking is too simplistic. In addition, I believe that multitasking belongs to the library, not to the language. LX will offer a multitasking library at some point, which I started discussing from an interface point of view on my web page somewhere. Most notably, with pragmas, you ensure that this seems integrated in the language, yet it remains outside of it. {synchronized} array Buffer[0..1023] of byte The Ada community discovered the hard way that building a given tasking model into the language was convenient, but ultimately closed too many doors. Real-time multitasking doesn't require the same primitives as web-server applications... A possible use in LX of a tasking model implemented in a library can be found at http://mozart-dev.sourceforge.net/lx_tasking.txt. It tries to mimic the "Ada" feel of tasking, but that's just one possible model. The Java feel is actually much simpler to implement :-) PS: I promise, if I ever complete a tasking library, it will have {synchronized} and {synchronised}, as well as {sincronised} for the spelling-impaired :-) Christophe |
August 17, 2001 Re: D vs. LX - Exceptions | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 22/ Try/Catch/Finally and destructors I agree with the model. As a matter of fact, this reminds me that I need to add finally as part of the try/catch statement in LX. On the other hand, there are many cases where destructors are indeed useful. For instance, locks, temporary files that need to be deleted when you exit a procedure or delete an object, etc. And it's not like the semantics or implementation is complicated either... Just avoid the X::~X syntax, and you will be fine. [LATER NOTE:] OK, you have destructors, and you do use the ~this syntax. Yuck... One important note: Bertrand Meyer, the author of Eiffel, makes a good point about what he calls "disciplined exceptions." Which means, in short, that by default, an exception repropagates rather than being "swallowed" by a catch. That's the model for LX. You need to use 'resume' to prevent the exception from propagating. The model is "catch clause as cleanup" rather than "catch clause as implicit fix". try do_stuff catch exception_A: fixup_A -- Implciitly rethrow here catch exception_B: fixup_B retry -- restart the 'try' block catch exception_C fixup_C resume -- C++ behavior here, quit the catch handler Optimization note: "finally" is actually very bad for some optimizations on "real, modern" CPUs (that is, not the x86 ;-) To Walter: that's largely because it makes the control flow much more complex, everything now connects to the finally, and the compiler must really take multiple exit pathes into consideration. Christophe |
August 17, 2001 Re: D vs. LX | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 33/ Complex numbers I believe that I can define in LX a complex type (and imaginary type) that is as optimized as your implementation. But, since it is in the library, I can also have: complex of ints, quaternions, tensors, etc. Why cover only complex numbers? Mathematics did not stop a couple of centuries ago :-) Well, someone else already made the point, methinks :-) Oh, by the way, since in LX most things are in the library, this makes several optimizations being actually resolved by operator overloading. For instance, for a processor that has a multiply-and-add instruction (PowerPC, IA-64) function Add(integer A, B) return integer written A+B {builtin add} function MulAdd(integer A, B, C) return integer written A*B+C {builtin mla} You can refer to the CVS repository on SourceForge to see how the LX compiler uses the {builtin} pragma to reference a table that defines the opcodes to emit to the assembler... Christophe |
August 17, 2001 Re: D vs. LX - HTML compilation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 34/ HTML compilation Ah, I see, you discarded the C preprocessor to replace it with an HTML preprocessor. So #include is being replaced with <A REF="http://....">. That's a clever trick. Seriously, I think this is a cute idea, but it has nothing to do with D. It is really a preprocessor that extracts source from HTML files, and that ought to be a separate tool... Christophe |
August 17, 2001 Re: D vs. LX - printf rules? AAaaaaaarrghhh! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | 35/ printf rules? printf sucks. Really. I could write 218918231231 pages on this. -- Unformatted IO IO.WriteLn "A=", A, " and then B=", B -- Formatted IO IO.WriteLn A format "A=####", B format "B="#5.9#" -- Definition of WriteLn generic type writable if with writable W IO.Write W procedure WriteLn() is Write Unicode.CR procedure WriteLn(writable X; others) is Write X WriteLn others Now, if you really care about the printf formatting idiotisms, you can implement that in LX too. Not that I would recommend it... Christophe |
August 17, 2001 Re: D vs. LX - Sieve in LX | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | My last post tonight, because I'm tired of typing... The sieve in LX. import IO = LX.Text_IO procedure main() is with integer i, count, prime, k, iter with bits flags[8191] for iter in 1..10 loop count := 0 flags[0..8191] := true for i in flags.index loop if flags[i] then prime := i+i+3 k := i + prime for k in i+prime..flags.index.high step prime loop flags[k] := false count += 1 IO.WriteLn count, " primes" And just because people will find bugs in my posts, let me mention it: there is a bug in the D implementation of the Sieve: it should be bit[8191] flags, methinks. Unless, of course, bit is special in that respect. It could be, it's a built-in type. And did I mention that built-in types are EVIL? Christophe |
August 17, 2001 Re: D vs. LX - Switch statement | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | Ach, a post by Chris Friesen reminded me about the switch statement. LX has two forms, one of them I care about, the other being just syntactic sugar. Syntactic sugar first: case when X > 0: do_something_with X when Y > 0: do_something_with Y when others: barf This is really another way to write "elseif". I initially thought I needed that construct because of the indent-sensitive syntax in LX, but it turns out that the indentation-checking is flexible enough to accomodate else if... I still kept the construct... The important one: procedure CheckInt(integer N) is case N is when 1: WriteLn "N is small" when 2..5: WriteLn "I can count N on one hand" when 6..10: WriteLn "I need to use two hands" when other: WriteLn "Sorry, can't do" What is interesting is that it uses a helper, variable-argument-size function to determine which case to take. So you can have a case statement with most anything. The helper function is called Index(X, T1, T2, ..., TN), and it returns the 1-based index of X inside the T1..TN objects. If none matches, it must return an out of range value (N+1 or 0 being good candidates) So for instance you can write an Index function that makes the following legal: procedure Hit(point P; rectangle R; circle C) is case P is when R: WriteLn "We hit the rectangle" when C: WriteLn "We hit the circle" when other: WriteLn "That's a miss... Christophe |
August 17, 2001 Re: D vs. LX - Delegation | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe de Dinechin | Ach, yet another post from the silly LX guy. Someone else talked about delegation. Delegation is probably the one thing that makes nEXtstEp (sorry, MacOS X 10.0.4.1 beta2 preview 3) implementable in Objective-C but not easily in C++. You ought to have this in D. A practical example: I have a window object, that can respond to several "messages" (display, resize, etc). On this window, I have several objects that know about some of the messages, but others they just don't care. One object which has the focus is the one that receives the messages from the operating system. The key issue here is: how do I forward messages that I don't care about to the window behind me, or to some other object that cares? Say the front widget interfcepts "Draw" messages, but just doesn't want to know anything about all others, such as "Resize", "Shutdown", etc... Let's try it the C++ way: class Window { virtual void Draw(...); virtual void Resize(...); ... // 12895 other members }; // Don't forget the semi-colon, it's really important, you know... OK, now, time to implement "widget". The key thing is that, from the operating system's point of view, Widget has to respond to the Window messages. So in C++, it derives from Window, right? Wrong! Let's try that first to see the problem. Assume for now that you try that for a Widget that cares only about the "Draw" message. class Widget : public Window { Window *behind_me; virtual void Draw(...) { /* something really great here */ } virtual void Resize(...) { behind_me->Resize(...); } // 12894 other members like Resize... }; The sad thing is that there is code out there actually written that way. Two major problems: it's very cumbersome to write, and the Widget inherits all of the Windows baggage, which it really doesn't care much about. And what if in MacOS X 10.0.4.1 beta2 preview 4, the OS vendor decides to add a member Recolor(...) in Window? Well, you are out of luck, because you do a very wrong thing with that: you just pass it to the base class, which thinks that it is the main window, and reformats your hard disk as a result. Other approaches: the Window base class may itself have a "delegate" field, and delegate everything. Not much better. There are a few other solutions. But ultimately, the only solutions that I saw working in C++ ran along the lines of having a single "SendMessage()" virtual function in the base class, and then a big switch statement that invokes other member functions. Which is just a way of implementing a much less efficient version of the Objective-C runtime system... In Objective-C, all message passing occurs in such a way that you can forward unknown messages to someone else, hoping that the receiving object knows what to do with it. Forwarding includes all method arguments, etc. In LX, a limited form of delegation is made possible by user-defined implicit conversions. I'm not completely satisfied with the solution yet. You would have: type window function Draw(window W, ...) function Resize(window W, ...) type widget with window Delegate function window(widget W) return window written W is return W.Delegate precedure Draw(widget W) -- Now you can write: procedure Test(widget W) Draw W -- Draw the widget Resize W -- Resize the window (delegate) As I said, I am not totally satisfied. Compared to Objective-C, it restores type safety (you give it up with the implicit conversion for only one type). On the other hand, it still has usability problems with dynamic dispatch and a few other things... Anyway, this is not about LX, it's about D, so if someone comes up with a cool solution in D... I'll be happy to borrow it for LX :-) Christophe |
Copyright © 1999-2021 by the D Language Foundation