digitalmars.D - Fully dynamic d by opDotExp overloading
- davidl (45/45) Apr 16 2009 After tweaking dmd a bit litte, i get the dotexp overloading work.
- Daniel Keep (5/5) Apr 16 2009 Very cool. What I'd like to see is this, TypeInfo_Struct.getMembers and
- davidl (5/10) Apr 17 2009 Thanks. I also hope for more runtime info.
- Don (3/19) Apr 16 2009 That's very impressive. How did you do it? Are the syntax and semantic
- davidl (8/24) Apr 17 2009 Yes, it follows the rule of rewriting the c.unknownmethod(args) to
- bearophile (8/9) Apr 17 2009 It's cute.
- Andrei Alexandrescu (6/61) Apr 17 2009 Cool! I suggest the rewrite:
- Denis Koroskin (2/52) Apr 17 2009 Yes, this also helps to catch errors at compile-time (like, dynObject.le...
- BCS (2/11) Apr 17 2009
- Christopher Wright (14/20) Apr 17 2009 How would that allow you to handle the method name dynamically, if
- Andrei Alexandrescu (25/49) Apr 17 2009 Of course. It makes no sense to ask for integrated syntax with a
- Christopher Wright (10/26) Apr 17 2009 It standardizes a system for dynamic method dispatch with arguments
- BCS (31/56) Apr 17 2009 the caller *can't* be dynamic, the calling code is known exactly at comp...
- Daniel Keep (49/53) Apr 17 2009 Careful. If you do that, you need to make sure it's possible to invoke
- Christopher Wright (10/24) Apr 18 2009 Yeah, that's one annoying thing about the proposal. There are a couple
- Danny Wilson (5/10) Apr 17 2009 Awesome, this is exactly what I thought was the point of 'opDot' when i ...
- Christopher Wright (6/7) Apr 17 2009 Do want.
- Leandro Lucarella (15/69) Apr 17 2009 This is awsome indeed. I'd love to see it in the specs. The suggestion o...
- Steven Schveighoffer (29/32) Apr 17 2009 I think it translates to
- Denis Koroskin (14/47) Apr 17 2009 Here is how it could be done:
- Andrei Alexandrescu (4/63) Apr 17 2009 I think the more urgent need is for static loops. At least we have a
- downs (9/77) Apr 18 2009 Static loops are simple, at least in functions.
- bearophile (11/17) Apr 18 2009 My dlibs have:
- downs (2/23) Apr 18 2009 Foreach on a tuple is evaluated at compile-time.
- bearophile (5/8) Apr 18 2009 Yes, that's the whole point of that Range!().
- Daniel Keep (5/15) Apr 18 2009 And you can't have it outside a function like you can static if. Also,
- downs (2/19) Apr 19 2009 Very true, but the _index_ should always be a constant.
- Andrei Alexandrescu (4/15) Apr 18 2009 I know, but at about the fiftienth one you get sick of it. And
- bearophile (4/5) Apr 18 2009 In some situations static loops can be useful, but in general isn't the ...
- BCS (4/16) Apr 18 2009 It's not just loop unrolling as some loops can't be "rolled" in the firs...
- Steven Schveighoffer (16/73) Apr 17 2009 Look! I found a way to implement this *in the current compiler*!:
- Andrei Alexandrescu (5/88) Apr 17 2009 Yah, glad someone mentioned it :o). The best way is a blend - you can
- Christopher Wright (22/27) Apr 17 2009 You suggest:
- Andrei Alexandrescu (18/51) Apr 17 2009 It's a good question. opDotExp leaves more flexibility because it allows...
- Jason House (2/59) Apr 17 2009 I find that funny. I can already imagine a developer that adds the equiv...
- BCS (2/6) Apr 17 2009 there is a daily WTF on that, but using URLs.
- Jarrett Billingsley (3/4) Apr 17 2009 Method name resolution using fuzzy string matching.
- Nick Sabalausky (11/27) Apr 18 2009 It's really late, so I can't come up with much coherent thought, but:
- davidl (17/49) Apr 17 2009 The opDotExp overload func is supposed to deal with that, because it's i...
- Steven Schveighoffer (22/78) Apr 17 2009 except, you can't define a property like:
- davidl (31/117) Apr 17 2009 But if you want a dynamic property, you won't want to do it in that way.
- Nick Sabalausky (26/28) Apr 17 2009 ...But you do have to write the opDotExp() function. How is that less wo...
- Steven Schveighoffer (22/58) Apr 17 2009 This is what I was talking about, but didn't thoroughly explain when I
- Nick Sabalausky (5/17) Apr 17 2009 That is a *very* good point, that hadn't even occured to me.
- Andrei Alexandrescu (21/46) Apr 17 2009 I think there's merit in binding via strings. It makes for very flexible...
- Steven Schveighoffer (29/71) Apr 17 2009 I guess I don't mind the dynamic lookup of methods, but I really don't
- Andrei Alexandrescu (12/47) Apr 17 2009 Yah, but that feeling of losing control often marks a paradigm shift (I
- davidl (8/84) Apr 17 2009 That's exactly what opDot can be capable of accomplishing. GetMethod is ...
- Don (2/53) Apr 17 2009
- Andrei Alexandrescu (8/15) Apr 17 2009 Of course. The template version includes the version that only does
- Don (10/29) Apr 17 2009 I was thinking that, for example, in a DLL, the DLL needs to include a
- Nick Sabalausky (31/42) Apr 17 2009 That's a separate issue. I absolutely agree with the usefulness of being...
- Andrei Alexandrescu (14/63) Apr 17 2009 I was expecting this objection. I think it's not based because unifying
- Don (3/39) Apr 17 2009 I'd even say that this feature is 100% syntax sugar. It doesn't add
- Nick Sabalausky (9/50) Apr 17 2009 Can you clarify what you mean here?
- davidl (8/66) Apr 17 2009 The opDot func can be extremely restrictive by looking up a former added...
- Don (8/35) Apr 17 2009 The problem is a lack of notification at compile time. Runtime
- Nick Sabalausky (3/39) Apr 17 2009 Ok, now *that* is something I can be happy with.
- Nick Sabalausky (8/20) Apr 17 2009 In fact, now that I think about it, as long as the member name was requi...
- Andrei Alexandrescu (23/47) Apr 18 2009 I think there's a confusion somewhere. Are you sure you know what you
- Nick Sabalausky (10/12) Apr 18 2009 Over here it's 3:30 in the morning at the moment: I don't know a damn th...
- Michel Fortin (31/46) Apr 18 2009 Andrei, I think you, and perhaps everyone here, are overlooking one
- Andrei Alexandrescu (14/66) Apr 18 2009 I'm confused. Isn't it clear that at the moment we "have" the ability to...
- Daniel Keep (8/63) Apr 18 2009 A related issue is that obj.opDotExp!"foo"(...) cannot be reflected over
- davidl (15/78) Apr 18 2009 Umm, actually you can... but with bad duplication in code:
- Andrei Alexandrescu (13/98) Apr 18 2009 What you want is:
- Michel Fortin (31/37) Apr 18 2009 Indeed, you can pass the template argument as a runtime argument to
- davidl (10/43) Apr 18 2009 Umm, right, you hunt the problem I didn't consider before.
- Don (11/57) Apr 18 2009 That's a very clear description.
- Andrei Alexandrescu (4/27) Apr 18 2009 Wrong. It's impossible to pass a dynamic string as a static string, so
- Michel Fortin (13/39) Apr 18 2009 Indeed it's impossible using a template which requires a static string.
- Andrei Alexandrescu (9/48) Apr 18 2009 I did, but sorry, it doesn't make sense and does nothing but continue
- Michel Fortin (131/138) Apr 19 2009 Then let's try to remove some of that confusion.
- Christopher Wright (32/63) Apr 19 2009 I agree with this wholeheartedly.
- Andrei Alexandrescu (22/29) Apr 19 2009 Thanks for doing so. Given that my wits are spent with regard to this
- Christopher Wright (6/31) Apr 19 2009 The utility is when you are looking for methods to invoke via runtime
- Andrei Alexandrescu (3/37) Apr 19 2009 Oddly enough, I got it now :o).
- Michel Fortin (10/28) Apr 19 2009 Thanks Cristopher. :-)
- BCS (4/11) Apr 19 2009 So it is being argued that there should be a standard way to do a run ti...
- Christopher Wright (3/18) Apr 20 2009 But there isn't, so this is YAGNI. And if there were, then this
- Michel Fortin (7/24) Apr 20 2009 The thing is that with compile-time reflection you can already build
- Christopher Wright (3/25) Apr 20 2009 You're telling me?
- BCS (21/60) Apr 18 2009 If opDotExp is a template you can do:
- Christopher Wright (3/7) Apr 17 2009 I don't think you can implement an interface with opDotExp, since it has...
- Don (25/50) Apr 17 2009 That's the VB/PHP nightmare -- allow any garbage to compile.
- Denis Koroskin (3/5) Apr 17 2009 I would consider it a "wrong direction". You won't use it *that* frequen...
- Denis Koroskin (2/7) Apr 17 2009 Err.. Should read: I woudn't consider it a "wrong direction".
- Andrei Alexandrescu (7/15) Apr 17 2009 Yah, for example Variant could define opDotExp to look whether the
- Christopher Wright (25/31) Apr 17 2009 It's more work, but it lets you do other interesting things.
- Nick Sabalausky (12/43) Apr 17 2009 Brainfuck and AppleScript are really neat, but I wouldn't want to write ...
- Rainer Deyke (15/23) Apr 17 2009 Compile time checking is not undermined at all, even for classes that
- Nick Sabalausky (8/33) Apr 17 2009 If the member-name parameter to opDotExp was *required* to be a template...
- Simen Kjaeraas (7/15) Apr 18 2009 As we can all clearly see, in obj.someDynamicFunction( "Foo!" ); "someDy...
- Danny Wilson (5/8) Apr 18 2009 I thought that would be the obvious application, and decided to mention ...
- Andrei Alexandrescu (6/21) Apr 17 2009 There are people who swear by the ability of adding methods at runtime
- Nick Sabalausky (3/6) Apr 17 2009 Personally, I've always seen that as extremely sloppy and haphazard.
- bearophile (6/11) Apr 17 2009 Adding methods at runtime is named "monkey patching", and it is consider...
- Yigal Chripun (7/23) Apr 17 2009 just like anything in life this can be overused. This is a very useful
- Steven Schveighoffer (7/32) Apr 17 2009 It's more like adding another outside door. Try doing that ;) (BTW,
- Yigal Chripun (20/54) Apr 17 2009 I completely disagree. here's a use case from my work:
- Nick Sabalausky (10/16) Apr 17 2009 Typically, yes, having "as many useful tools as possible in our programm...
- Andrei Alexandrescu (4/23) Apr 17 2009 I don't think this argument holds.
- Steven Schveighoffer (11/29) Apr 17 2009 Sure, how do you know that the class actively chose it, or did not
- Andrei Alexandrescu (10/42) Apr 17 2009 You shouldn't worry about it as much as you shouldn't when you iterate a...
- Nick Sabalausky (16/25) Apr 17 2009 That's an inadequate comparison. We *can* make arrays and ranges usable ...
- Andrei Alexandrescu (37/66) Apr 17 2009 Au contraire, it's a very adequate comparison. We changed the language
- Steven Schveighoffer (23/86) Apr 17 2009 Calling global functions as if they were array members does not subvert ...
- Steven Schveighoffer (14/21) Apr 17 2009 Let me add that if there was a way for syntax to easily allow for
- Don (2/28) Apr 17 2009
- Christopher Wright (2/20) Apr 18 2009 Not an option. I want to dispatch to methods that might throw exceptions...
- Christopher Wright (4/30) Apr 18 2009 Or if the type you are dealing with is irrevocably weakly typed anyway,
- Steven Schveighoffer (35/56) Apr 18 2009 I gave this a lot of thought, and I think here is a possible solution:
- Andrei Alexandrescu (13/34) Apr 18 2009 class X
- Steven Schveighoffer (17/47) Apr 18 2009 Yeah, I get that it can be done manually. What I'm suggesting is that t...
- Don (3/55) Apr 18 2009 You'll get a "missing return statement", except in the case where it's
- Steven Schveighoffer (4/23) Apr 19 2009 I thought that the point of the auto return is that the dynamic function...
- Denis Koroskin (29/89) Apr 18 2009 Here is an example of a more sophisticated opDotExp use case that relies...
- Daniel Keep (5/19) Apr 17 2009 So we have to write ALL templated code that calls member functions or
- Nick Sabalausky (8/27) Apr 17 2009 No, only ones that absolutely need to work with dynamic classes. Which i...
- Andrei Alexandrescu (12/44) Apr 17 2009 But you're getting it exactly, almost rigorously, backwards. Algorithms
- Andrei Alexandrescu (7/85) Apr 17 2009 Of course I agree. The thing is, if you decide to use a dynamic type,
- Nick Sabalausky (15/30) Apr 17 2009 I didn't have a problem with that reasoning when Variant was added, beca...
- Yigal Chripun (10/15) Apr 18 2009 Here's an idea:
- Andrei Alexandrescu (4/24) Apr 18 2009 The dynamic behavior is indicated by the use of opDotExp. The redundancy...
- Danny Wilson (14/20) Apr 18 2009 Not necessarily.
- BCS (4/9) Apr 18 2009 not exactly 1-to-1 but:
- Denis Koroskin (3/11) Apr 18 2009 Bad example:
- BCS (2/7) Apr 18 2009 So I saw, I'm just saying it's not without precedent.
- Nick Sabalausky (20/28) Apr 17 2009 Right, that's what I meant, but that's still worse than not having opDot...
- Danny Wilson (24/34) Apr 18 2009 class AbstractConceptInvoker
- Danny Wilson (14/22) Apr 18 2009 What I was really trying to say is: sure you have to keep track of which...
- Benji Smith (23/37) Apr 27 2009 Incidentally, one ugly problem with using opDotExp is that the
- Adam D. Ruppe (8/12) Apr 17 2009 Wouldn't the compile time checking remain the same on any class except
- Nick Sabalausky (7/17) Apr 17 2009 The problem is there would be no way to tell at a glance whether a given...
- Andrei Alexandrescu (9/31) Apr 17 2009 Then why overloadable operators? Just write a function call and call it
- Nick Sabalausky (22/30) Apr 17 2009 Overloadable operators and opDotExp both sacrifice code transparency. In...
- Andrei Alexandrescu (4/8) Apr 17 2009 Given my track record, I think it should come at no surprise that I'm
- Jason House (4/14) Apr 17 2009 I'm no fan of it either. I will be pissed if one day I'm using a D libra...
- Adam Burton (102/129) Apr 18 2009 I agree.
- Andrei Alexandrescu (4/37) Apr 18 2009 That's absolutely useless. If I have to write anything different from
- Adam Burton (4/43) Apr 18 2009 You could even write 'noodles' but that doesn't really give me a reason ...
- Andrei Alexandrescu (7/16) Apr 18 2009 I apologize for the snapping. There's no excuse really, but let me
- Adam D. Ruppe (12/17) Apr 18 2009 What if the dot remained exactly like it is now and the -> took
- BCS (5/17) Apr 18 2009 Going the other way would be better; '.' works as Andrei wants and '->' ...
- Adam Burton (279/300) Apr 19 2009 Yea and that would be bad, since then as far as I am concerned you have
- Adam Burton (28/377) Apr 19 2009 Just thought as well, in a dynamic template call you would probably disa...
- BCS (12/49) Apr 19 2009 I see your point but disagree. I see it more as a "what to do if the cod...
- Adam Burton (36/88) Apr 19 2009 That's essentially what I was trying to say. What I was adding is that w...
- BCS (4/21) Apr 19 2009 OK, it seems that we agree on the one point I'm still interested in runn...
- Steven Schveighoffer (13/28) Apr 18 2009 Hm... the thought just occurred to me.
- Denis Koroskin (6/31) Apr 19 2009 Variant variantRange = someRange();
- Adam Burton (6/45) Apr 19 2009 I agree, seems to me templates attempt to acheive the same as dynamic ca...
- Steven Schveighoffer (6/44) Apr 19 2009 Doesn't the current opDot solution do this? Forwarding all calls to a
- Steven Schveighoffer (7/54) Apr 19 2009 Not to mention, how does the compiler know that it should use range-styl...
- Denis Koroskin (14/62) Apr 19 2009 opDot is reprecated (use alias this instead) and will be eventually remo...
- Steven Schveighoffer (21/93) Apr 19 2009 Yes, there are many things that opDotExp can do that opDot or alias this...
- BCS (4/8) Apr 19 2009 split the difference and allow either (but not both):
- Denis Koroskin (3/22) Apr 20 2009 Oh, right, I saw his post but forgot that solution. Thanks you!
- Steven Schveighoffer (15/36) Apr 20 2009 No
- Andrei Alexandrescu (5/48) Apr 20 2009 Good point. My take is, just have the compiler rewrite a.b(c, d, e) into...
- Steven Schveighoffer (9/52) Apr 20 2009 Haven't used D2 for much stuff, but does this work? I remember reading ...
- Andrei Alexandrescu (4/16) Apr 20 2009 It should, but there's a bug related to variadics (right now it only
- Andrei Alexandrescu (5/21) Apr 20 2009 Found it. Walter seems to get genuinely interested in opDot so vote up,
- Simen Kjaeraas (11/20) Apr 19 2009 One use I can see for this is the other opDotExp use that's been mention...
- Leandro Lucarella (14/35) Apr 17 2009 This is like foreach. In C a for loop is a for loop, you are never calli...
- Andrei Alexandrescu (5/39) Apr 17 2009 It's more than just convenience; it's integration. Uniform form allows
- Nick Sabalausky (9/29) Apr 17 2009 There a point I keep bringing up that keeps getting ignored: the
- Leandro Lucarella (15/31) Apr 17 2009 What do you call "non-trivial"?
- Yigal Chripun (5/23) Apr 17 2009 I was talking generally about dynamic vs. static typing and didn't
- Nick Sabalausky (11/28) Apr 17 2009 Interesting, I didn't know that.
- bearophile (12/15) Apr 17 2009 This is a very old discussion about the pro/cons of dynamic/static typin...
- Nick Sabalausky (3/5) Apr 17 2009 Maybe so, but I don't see any real benefit from it.
- bearophile (5/6) Apr 17 2009 Are you asking me suggestions to help you see such benefits? :-)
- Christopher Wright (6/27) Apr 17 2009 Assuming that you are testing the logic of your application, you will
- Nick Sabalausky (5/10) Apr 17 2009 I don't think I understand what you're trying to say. With static langua...
- Christopher Wright (8/20) Apr 18 2009 And let's say your object suddenly gets a "legnth" field because it's
- BCS (6/10) Apr 18 2009 IIRC dynamic language do gobs of TDD/unittests because they have no choi...
- Leandro Lucarella (11/18) Apr 17 2009 RPC is an example that comes into mind
- Nick Sabalausky (11/18) Apr 17 2009 But is there any that can't be done with a dispatch function?
- Leandro Lucarella (19/41) Apr 17 2009 You can write anything even with brainfuck. There are no discussion abou...
- Nick Sabalausky (30/65) Apr 17 2009 Please, please, please, let's not delve into the "everything can be done...
- Leandro Lucarella (10/61) Apr 18 2009 Uniform (and better) syntax. It's just about that.
- SandeepK (11/16) Apr 18 2009 I too am having difficulty in understanding the benefit of this particul...
- bearophile (14/19) Apr 18 2009 It can be unknown at compile-time.
- Don (4/23) Apr 18 2009 I don't see _anything_ dynamic in this proposal, actually.
- Andrei Alexandrescu (10/11) Apr 18 2009 Yes. The amount of confusion in this thread is staggering. I think the
- bearophile (4/5) Apr 18 2009 I think I have misunderstood about the whole thread then. If the string ...
- Andrei Alexandrescu (7/14) Apr 18 2009 In the syntax
- davidl (38/53) Apr 18 2009 Depends on the compiler semantic. The compiler can feed the opDot with t...
- Andrei Alexandrescu (4/30) Apr 18 2009 I agree it "can". I don't agree it "can if it's not out of its mind".
- Yigal Chripun (6/23) Apr 18 2009 what prevents D from having an eval function?
- Andrei Alexandrescu (3/28) Apr 18 2009 Sure it is possible. It has zero relevance to the topic at hand.
- BCS (3/24) Apr 18 2009 Even then it is *still* going to be compile time. Just a compile time ru...
- Yigal Chripun (5/30) Apr 18 2009 No it won't. you will call a standard library API at *runtime* with a
- BCS (17/52) Apr 19 2009 That is exactly what I was thinking of and something I have wanted for s...
- Yigal Chripun (22/76) Apr 19 2009 everything you said is true. there is some sort of a compile-time since
- BCS (36/60) Apr 19 2009 I think you understand my point about what is possible but I'm not sure ...
- BCS (9/22) Apr 19 2009 Hello BCS,
- Yigal Chripun (16/66) Apr 19 2009 I was meaning static as in "static if".
- BCS (17/33) Apr 20 2009 But one is interpreted and the other manifests as machine code, one can ...
- Simen Kjaeraas (5/10) Apr 18 2009 I suggest you read Burton Radons' "The Joy and Gibbering Terror of Custo...
- Christopher Wright (15/22) Apr 18 2009 There are two issues here:
- davidl (10/25) Apr 17 2009 Actually this can help ddl project to work more nicely. Consider you can...
- davidl (6/35) Apr 17 2009 DDBI can also benefit from it.
- Steven Schveighoffer (8/46) Apr 17 2009 Yes, this case does make sense, but I would still probably rather write ...
- davidl (11/60) Apr 17 2009 Actually in a lot cases, you don't have the time to write the static
- Nick Sabalausky (7/16) Apr 17 2009 Solution: Create a dispatch function like callfunc above, then use a mix...
- Don (9/64) Apr 17 2009 I believe it is entirely syntax sugar. It's no different to:
- Nick Sabalausky (9/21) Apr 17 2009 I think some sort of paramaterized property would be far better (I *thin...
- Leandro Lucarella (9/15) Apr 17 2009 Being able to do it doesn't mean you have to use it always. You don't
- Don (5/14) Apr 17 2009 Correction: You don't lose anything if *nobody you interact with* uses
- Andrei Alexandrescu (5/22) Apr 17 2009 On the other hand, using the feature requires some due diligence. It
- bearophile (4/6) Apr 17 2009 It adds complexity to the language. More things to know and remember and...
- Andrei Alexandrescu (4/12) Apr 17 2009 I agree. I think in this case the complexity addition is well worth the
- davidl (7/70) Apr 17 2009 Thanks, the example here v.qq returns a B object, and then the assignmen...
- bearophile (13/17) Apr 18 2009 I can show something even more extreme :-)
- Daniel Keep (5/27) Apr 18 2009 There's an interesting idea...
- Andrei Alexandrescu (5/35) Apr 18 2009 Heh. The string kernels in std.numeric
- Walter Bright (4/13) Apr 18 2009 I remember, but can't find, some famous programmer posted to the net a
- Andrei Alexandrescu (10/24) Apr 18 2009 I don't know who the famous programmer was but it sounds like he was
- Walter Bright (1/1) Apr 18 2009 A simple command line spell checker would be a cool demonstration of thi...
- Georg Wrede (10/11) Apr 18 2009 $ man bash
- Leandro Lucarella (13/37) Apr 18 2009 Git[1] added that feature for Git commands recently and even when it's n...
- Walter Bright (3/4) Nov 28 2009 And here it is (called opDispatch, Michel Fortin's suggestion):
- bearophile (5/6) Nov 28 2009 That's short code.
- Walter Bright (3/8) Nov 28 2009 opDispatch can be written to do runtime method names, no language
- bearophile (5/7) Nov 28 2009 Very good. Then the opDynamic name wasn't wrong.
- Walter Bright (12/13) Nov 28 2009 class C
- Simen kjaeraas (18/22) Nov 28 2009 Just tested it - it does not seem to allow template parameters beyond ju...
- Walter Bright (2/18) Nov 28 2009 I see. That's a bug, and I'll fix it.
After tweaking dmd a bit litte, i get the dotexp overloading work. The following is the test code: import std.stdio; class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); } void opAdd(int j) { } void test() { } } class a:c { } class B { int i; B opAssign(int k){ i=k; return this; } } char[] v1; void func(char[] v, ...){} void main() { a v=new a; v.test(); v.dynamicmethod(3,4); //v.qq = 5; writefln((v.qq = 5).i); } it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature? -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 16 2009
Very cool. What I'd like to see is this, TypeInfo_Struct.getMembers and ClassInfo.getMembers. Once we have all three, we could do some incredibly awesome things. Like implement Objective C-style message passing as a library. :D -- Daniel
Apr 16 2009
在 Fri, 17 Apr 2009 14:44:46 +0800,Daniel Keep <daniel.keep.lists gmail.com> 写道:Very cool. What I'd like to see is this, TypeInfo_Struct.getMembers and ClassInfo.getMembers. Once we have all three, we could do some incredibly awesome things. Like implement Objective C-style message passing as a library. :D -- DanielThanks. I also hope for more runtime info. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 17 2009
davidl wrote:After tweaking dmd a bit litte, i get the dotexp overloading work. class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); }it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?That's very impressive. How did you do it? Are the syntax and semantic passes still independent?
Apr 16 2009
在 Fri, 17 Apr 2009 14:52:30 +0800,Don <nospam nospam.com> 写道:davidl wrote:Yes, it follows the rule of rewriting the c.unknownmethod(args) to c.opDotExp("unknownmethod", args); Though it currently gets bugs of not supporting struct, opDotExp signiture must be (char[],...), and possibly break extension method. These should all be fixable. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/After tweaking dmd a bit litte, i get the dotexp overloading work. class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); }it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?That's very impressive. How did you do it? Are the syntax and semantic passes still independent?
Apr 17 2009
davidl:Any comments? Do you like this feature?It's cute. Maybe "." can be used for static methods and some other syntax for dynamic ones, like: v..dynamicmethod(x); v->dynamicmethod(x); It seems that after releasing DMD source code the head of the cat is finally starting to come out of Walter's bag :-) This is for the better. Bye, bearophile
Apr 17 2009
davidl wrote:After tweaking dmd a bit litte, i get the dotexp overloading work. The following is the test code: import std.stdio; class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); } void opAdd(int j) { } void test() { } } class a:c { } class B { int i; B opAssign(int k){ i=k; return this; } } char[] v1; void func(char[] v, ...){} void main() { a v=new a; v.test(); v.dynamicmethod(3,4); //v.qq = 5; writefln((v.qq = 5).i); } it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically. Andrei
Apr 17 2009
On Fri, 17 Apr 2009 13:25:45 +0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:davidl wrote:Yes, this also helps to catch errors at compile-time (like, dynObject.lenght vs dynObject.length).After tweaking dmd a bit litte, i get the dotexp overloading work. The following is the test code: import std.stdio; class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); } void opAdd(int j) { } void test() { } } class a:c { } class B { int i; B opAssign(int k){ i=k; return this; } } char[] v1; void func(char[] v, ...){} void main() { a v=new a; v.test(); v.dynamicmethod(3,4); //v.qq = 5; writefln((v.qq = 5).i); } it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically. Andrei
Apr 17 2009
Reply to Andrei,Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args)vote++;That way you have the option of handling the method name statically or dynamically. Andrei
Apr 17 2009
Andrei Alexandrescu wrote:Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.How would that allow you to handle the method name dynamically, if you're passing it as a template argument? You mean that the *callee* can be dynamic. However, the *caller* cannot. This would rarely be an issue, I grant, but: Let's say you have a set of valid arguments for the opDotExp template. Why the hell aren't you writing individual methods?! So opDotExp is nearly useless if you make the method name a template argument. The *only* uses are - blacklisting arguments, with compile-time errors - requiring that arguments follow a certain (regular) pattern, with compile-time errors - a way to get the __FUNCTION__ macro that's been requested several times and not yet implemented
Apr 17 2009
Christopher Wright wrote:Andrei Alexandrescu wrote:Of course. It makes no sense to ask for integrated syntax with a variable string. Think of it for a minute.Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.How would that allow you to handle the method name dynamically, if you're passing it as a template argument? You mean that the *callee* can be dynamic. However, the *caller* cannot.This would rarely be an issue, I grant, but: Let's say you have a set of valid arguments for the opDotExp template. Why the hell aren't you writing individual methods?! So opDotExp is nearly useless if you make the method name a template argument. The *only* uses are - blacklisting arguments, with compile-time errors - requiring that arguments follow a certain (regular) pattern, with compile-time errors - a way to get the __FUNCTION__ macro that's been requested several times and not yet implementedI don't think I quite understand. Let me repeat: passing the string as a template gives you static+dynamic. Passing the string as a runtime value gives you dynamic. To clarify: class Dynamo { Variant call(string name, Variant[] args...) { ... } Variant opDotExp(string name, T...)(T args) { return call(name, variantArray(args)); } ... } Now you can say: Dynamo d; d.foo(); string bar = chomp(readln); d.call(bar); Makes sense? Andrei
Apr 17 2009
Andrei Alexandrescu wrote:Christopher Wright wrote:It standardizes a system for dynamic method dispatch with arguments generated at runtime or compile time. For arguments generated at compile time, it provides syntactic sugar. Yours standardizes a system for dynamic method dispatch with arguments generated at compile time, and provides syntactic sugar. It also provides some minor opportunities for partial compile-time checking for these arguments. In the end, I think that standardization of the runtime portions isn't so important. I accede.Andrei Alexandrescu wrote:Of course. It makes no sense to ask for integrated syntax with a variable string. Think of it for a minute.Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.How would that allow you to handle the method name dynamically, if you're passing it as a template argument? You mean that the *callee* can be dynamic. However, the *caller* cannot.
Apr 17 2009
Reply to Christopher,Andrei Alexandrescu wrote:the caller *can't* be dynamic, the calling code is known exactly at compile time. If you want to be able to call a function by name or by the normal syntax use: void CallByName(char[] name, args...) {...} void opDot(char[] name)(args...) { CallByName(name, args ...); } // one line, will get inlined if anything ever does.Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.How would that allow you to handle the method name dynamically, if you're passing it as a template argument? You mean that the *callee* can be dynamic. However, the *caller* cannot. This would rarely be an issue, I grant, but:Let's say you have a set of valid arguments for the opDotExp template. Why the hell aren't you writing individual methods?!for one: struct S(T) { T* t; void opDot!(char[] name)(U u) { mixin("t." ~name~ "(v);"); } } also haveing a large set of function where you can compute the meaning from the name: void Foo(){...} void FooBar(){...} void Bar(){...} //LogFoo //LogFooBar //LogBar void opDot(char[] name)() { static assert(name.length > 3 && name[0..3] == "Log") writelf("Calling "~ name[3..$]); mixin(name[3..$]~"();"); writelf("Called "~ name[3..$]); }So opDotExp is nearly useless if you make the method name a template argument. The *only* uses are - blacklisting arguments, with compile-time errors - requiring that arguments follow a certain (regular) pattern, with compile-time errors - a way to get the __FUNCTION__ macro that's been requested several times and not yet implemented
Apr 17 2009
Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.Careful. If you do that, you need to make sure it's possible to invoke a given method at runtime. Assuming getMembers is implemented (I make daily sacrifices in hopes of that), each distinct opDotExpr!(s) needs to get an entry. Otherwise, you've ironically created something that's HARDER to programatically invoke. :P A few more comments. There seem to be a few arguments being given against this. First is one of syntax: if this gets in to the language, you won't be able to tell whether a given member access actually works or not, so it should have a unique syntax. The problem with this is that if you do that you might as well not bother at all; dynamic dispatch objects will never be able to participate in templates. Unless, of course, you always write templates using dynamic dispatch syntax, at which point you've just nullified the benefits of doing so since now you can't tell whether a given call will work or not until runtime. It either goes into the language with "normal" syntax and is used sparingly, or it goes in with special syntax and is either never used (or when it is used it is limited in where it can be used) or everything switches over to the special syntax. As much as I would prefer to see dynamic dispatch have a special syntax or marker of some sort, since I actually want to see it in the language, I have to go with the first option. The other argument against is that there isn't a sufficient benefit to doing this. I'd argue that there is. Off the top of my head: * Swizzling: given a 4D vector, there are 256 possible swizzling operations. With dynamic dispatch, you can define them only as needed without extra syntax. * XML-RPC: Python has the best interface for this, hands down: just connect to the service and go nuts. * Message-passing: I had a big app a few years ago that was designed around this. Everything went through a central messaging object. Without this sort of syntax, I and everyone else would have gone mad from continually writing `msgSink.sendMessage("blah")` everywhere when `msgSink.blah` was perfectly unambiguous. There ARE benefits to this sort of ability. I don't think this would be something that you'd see everywhere; it'd be relegated to a few specific types where it makes sense. Hell, you could probably make Descent highlight such objects with a different colour so you always know. You CAN achieve a similar effect without special syntax. But you can do foreach without foreach. And you don't need scope. Or classes. Or symbols. The two questions are: is it useful and is it worth the effort. The first is definitely true from my experience, and I'm not sure we can answer the second until we get some time with it to see how well it works. Perhaps davidl could release his patch so it can be played with? :D -- Daniel
Apr 17 2009
Daniel Keep wrote:Yeah, that's one annoying thing about the proposal. There are a couple of solutions: - Let types with opDotExp manipulate their type information dynamically. This would be a *lot* of work, and it wouldn't necessarily work for everything (let's say one instance of the class has some methods available and another one has different ones available). - Allow template instantiations to be included in type information. This will require patching type info again, for instance when you compile files separately and instantiate the templates in different modules.Cool! I suggest the rewrite: c.unknownmethod(args) -> c.opDotExp!("unknownmethod")(args) That way you have the option of handling the method name statically or dynamically.Careful. If you do that, you need to make sure it's possible to invoke a given method at runtime. Assuming getMembers is implemented (I make daily sacrifices in hopes of that), each distinct opDotExpr!(s) needs to get an entry. Otherwise, you've ironically created something that's HARDER to programatically invoke. :P
Apr 18 2009
Op Fri, 17 Apr 2009 08:31:02 +0200 schreef davidl <davidl nospam.org>:it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?Awesome, this is exactly what I thought was the point of 'opDot' when i first skimmed over it in the docs. This is great for lots of purposes. A small nice example is: http://haxe.org/doc/advanced/xml_fast
Apr 17 2009
davidl wrote:After tweaking dmd a bit litte, i get the dotexp overloading work.Do want. With this and extended runtime information, you can create a Variant that works exactly like the original type, allowing you to call methods on it without extracting it to the original type, just throwing an ArgumentException or MethodMissingException if you give it something bad.
Apr 17 2009
davidl, el 17 de abril a las 14:31 me escribiste:After tweaking dmd a bit litte, i get the dotexp overloading work. The following is the test code: import std.stdio; class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); } void opAdd(int j) { } void test() { } } class a:c { } class B { int i; B opAssign(int k){ i=k; return this; } } char[] v1; void func(char[] v, ...){} void main() { a v=new a; v.test(); v.dynamicmethod(3,4); //v.qq = 5; writefln((v.qq = 5).i); } it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?This is awsome indeed. I'd love to see it in the specs. The suggestion of making opDotExp a template it's good one too. I guess that now that opDot is replaced by alias this, opDot can be used for this instead of opDotExp. I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()? Thanks for the great job. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Que barbaridad, este pa铆s se va cada ves m谩s pa' tras, m谩s pa' tras... -- Sidharta Kiwi
Apr 17 2009
On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 17 2009
On Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Here is how it could be done: class C { auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot { static if (methodName == "length") { return _length; // return type is size_t } else static if (methodName == "resize") { _resize(args); // return type is void } } } This is a great use-case for compile-time "static switch". Can we haz one, please?I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 17 2009
Denis Koroskin wrote:On Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I think the more urgent need is for static loops. At least we have a simple workaround for static switch. AndreiOn Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Here is how it could be done: class C { auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot { static if (methodName == "length") { return _length; // return type is size_t } else static if (methodName == "resize") { _resize(args); // return type is void } } } This is a great use-case for compile-time "static switch". Can we haz one, please?I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 17 2009
Andrei Alexandrescu wrote:Denis Koroskin wrote:Static loops are simple, at least in functions. import std.stdio; template Tuple(T...) { alias T Tuple; } template Repeat(T, int I) { static if (!I) alias Tuple!() Repeat; else alias Tuple!(T, Repeat!(T, I-1)) Repeat; } void main() { foreach (i, bogus; Repeat!(void, 15)) writefln(i); }On Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I think the more urgent need is for static loops. At least we have a simple workaround for static switch. AndreiOn Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Here is how it could be done: class C { auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot { static if (methodName == "length") { return _length; // return type is size_t } else static if (methodName == "resize") { _resize(args); // return type is void } } } This is a great use-case for compile-time "static switch". Can we haz one, please?I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 18 2009
downs:Static loops are simple, at least in functions. ... void main() { foreach (i, bogus; Repeat!(void, 15)) writefln(i); }My dlibs have: Range!([start], stop[, step]) with it I think your code becomes: void main() { foreach (i; Range!(15)) putr(i); } But a static foreach (on a static data structure that has opApply) is not doable yet, I think. Bye, bearophile
Apr 18 2009
bearophile wrote:downs:Foreach on a tuple is evaluated at compile-time.Static loops are simple, at least in functions. ... void main() { foreach (i, bogus; Repeat!(void, 15)) writefln(i); }My dlibs have: Range!([start], stop[, step]) with it I think your code becomes: void main() { foreach (i; Range!(15)) putr(i); } But a static foreach (on a static data structure that has opApply) is not doable yet, I think. Bye, bearophile
Apr 18 2009
downs:bearophile:Yes, that's the whole point of that Range!(). But you can't use that trick on an associative array, or a struct with OpApply, etc. Bye, bearophileBut a static foreach (on a static data structure that has opApply) is not doable yet, I think.Foreach on a tuple is evaluated at compile-time.
Apr 18 2009
bearophile wrote:downs:And you can't have it outside a function like you can static if. Also, there are various bugs relating to the values being iterated over sometimes kinda-but-not-really being compile-time constants. -- Danielbearophile:Yes, that's the whole point of that Range!(). But you can't use that trick on an associative array, or a struct with OpApply, etc. Bye, bearophileBut a static foreach (on a static data structure that has opApply) is not doable yet, I think.Foreach on a tuple is evaluated at compile-time.
Apr 18 2009
Daniel Keep wrote:bearophile wrote:Very true, but the _index_ should always be a constant.downs:And you can't have it outside a function like you can static if. Also, there are various bugs relating to the values being iterated over sometimes kinda-but-not-really being compile-time constants. -- Danielbearophile:Yes, that's the whole point of that Range!(). But you can't use that trick on an associative array, or a struct with OpApply, etc. Bye, bearophileBut a static foreach (on a static data structure that has opApply) is not doable yet, I think.Foreach on a tuple is evaluated at compile-time.
Apr 19 2009
downs wrote:Static loops are simple, at least in functions. import std.stdio; template Tuple(T...) { alias T Tuple; } template Repeat(T, int I) { static if (!I) alias Tuple!() Repeat; else alias Tuple!(T, Repeat!(T, I-1)) Repeat; } void main() { foreach (i, bogus; Repeat!(void, 15)) writefln(i); }I know, but at about the fiftienth one you get sick of it. And generating code in a static loop is much harder. Andrei
Apr 18 2009
Andrei Alexandrescu:I know, but at about the fiftienth one you get sick of it.In some situations static loops can be useful, but in general isn't the compiler supposed to be able to perform loop unrolling by itself, according to compilation arguments and according to how much code is present into the loop? (if it's too much code then loop unrolling is to be avoided). Bye, bearophile
Apr 18 2009
Hello bearophile,Andrei Alexandrescu:It's not just loop unrolling as some loops can't be "rolled" in the first place, like when one of the loop variables is a type or you need to static if on the index.I know, but at about the fiftienth one you get sick of it.In some situations static loops can be useful, but in general isn't the compiler supposed to be able to perform loop unrolling by itself, according to compilation arguments and according to how much code is present into the loop? (if it's too much code then loop unrolling is to be avoided). Bye, bearophile
Apr 18 2009
On Fri, 17 Apr 2009 10:32:04 -0400, Denis Koroskin <2korden gmail.com> wrote:On Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Look! I found a way to implement this *in the current compiler*!: class C { size_t length() { return _length; } void resize(T...)(T args) { _resize(args); } } sorry, couldn't help myself :P -SteveOn Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Here is how it could be done: class C { auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot { static if (methodName == "length") { return _length; // return type is size_t } else static if (methodName == "resize") { _resize(args); // return type is void } } }I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 10:32:04 -0400, Denis Koroskin <2korden gmail.com> wrote:Yah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff. AndreiOn Fri, 17 Apr 2009 18:24:04 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Look! I found a way to implement this *in the current compiler*!: class C { size_t length() { return _length; } void resize(T...)(T args) { _resize(args); } } sorry, couldn't help myself :P -SteveOn Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Here is how it could be done: class C { auto opDot(string methodName, T... args)(T args) // opDotExp renamed to opDot { static if (methodName == "length") { return _length; // return type is size_t } else static if (methodName == "resize") { _resize(args); // return type is void } } }I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception } Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types. -Steve
Apr 17 2009
Andrei Alexandrescu wrote:Yah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff. AndreiYou suggest: auto opDotExp(string name)(...) { static if (name == "something") { code... } else { dynamic stuff } } That isn't very clear. Why not write it this way: auto opDotExp(string name, ...) { dynamic stuff } auto something (...) { code... }
Apr 17 2009
Christopher Wright wrote:Andrei Alexandrescu wrote:It's a good question. opDotExp leaves more flexibility because it allows for a host of compile-time manipulations, e.g. decide to forward to a member etc. Also consider this (probably Nick will turn blue): struct Pascalize(T) { T m; auto opDotExp(string name, T...)(T args) { return mixin("m."~tolower(name))(args); } } struct S { void foo() { ... } } Pascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works again AndreiYah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff. AndreiYou suggest: auto opDotExp(string name)(...) { static if (name == "something") { code... } else { dynamic stuff } } That isn't very clear. Why not write it this way: auto opDotExp(string name, ...) { dynamic stuff } auto something (...) { code... }
Apr 17 2009
Andrei Alexandrescu Wrote:Christopher Wright wrote:I find that funny. I can already imagine a developer that adds the equivalent of autocorrection while they type because they make trivial typos all teh timrAndrei Alexandrescu wrote:It's a good question. opDotExp leaves more flexibility because it allows for a host of compile-time manipulations, e.g. decide to forward to a member etc. Also consider this (probably Nick will turn blue): struct Pascalize(T) { T m; auto opDotExp(string name, T...)(T args) { return mixin("m."~tolower(name))(args); } } struct S { void foo() { ... } } Pascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works again AndreiYah, glad someone mentioned it :o). The best way is a blend - you can statically dispatch on some popular/heavily-used names, then rely on a hashtable lookup for dynamic stuff. AndreiYou suggest: auto opDotExp(string name)(...) { static if (name == "something") { code... } else { dynamic stuff } } That isn't very clear. Why not write it this way: auto opDotExp(string name, ...) { dynamic stuff } auto something (...) { code... }
Apr 17 2009
Hello Jason,I find that funny. I can already imagine a developer that adds the equivalent of autocorrection while they type because they make trivial typos all teh timrthere is a daily WTF on that, but using URLs.
Apr 17 2009
On Fri, Apr 17, 2009 at 9:47 PM, Jason House <jason.james.house gmail.com> wrote:I find that funny. I can already imagine a developer that adds the equivalent of autocorrection while they type because they make trivial typos all teh timrMethod name resolution using fuzzy string matching.
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsav4n$2ij4$1 digitalmars.com...It's a good question. opDotExp leaves more flexibility because it allows for a host of compile-time manipulations, e.g. decide to forward to a member etc. Also consider this (probably Nick will turn blue): struct Pascalize(T) { T m; auto opDotExp(string name, T...)(T args) { return mixin("m."~tolower(name))(args); } } struct S { void foo() { ... } } Pascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works againIt's really late, so I can't come up with much coherent thought, but: 1. Ick. 2. Wasn't the potential for just that sort of abuse a big part of the reason for ditching #define? 3. struct F { void fooBar() { ... } } Pascalize!F f; // Can't invoke shit! // Don't ask me what point I'm trying to make with that, // I don't even know, myself.
Apr 18 2009
在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:The opDotExp overload func is supposed to deal with that, because it's in your hand to deal with the dynamic properties. The example here is illustrating the dynamic properties.I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception }The problem is you're dealing with the class which is overloaded its opDot. You know the risk before hand, you are not going to overload for every classes. Here, you seem to little bit overrate this feature. :) If you want things checked, then you probabely need to go back to static. This dynamic stuff is used for dynamic things only, and as long as you have to do it in the dynamic way that means you have no easy way or even impossible to check it at compiletime and you accept the potential risk like the example you posted.Also, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types.Umm, maybe make the compiler to pass the return type into the opDot would allow the opDot func to decide which overload func to call. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 17 2009
On Fri, 17 Apr 2009 11:11:55 -0400, davidl <davidl nospam.org> wrote:鍦 Fri, 17 Apr 2009 22:24:04 +0800锛孲teven Schveighoffer <schveiguy yahoo.com> 鍐欓亾:except, you can't define a property like: void prop(int x) { _prop = x ^ ~0; } Using a dynamic method.On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:The opDotExp overload func is supposed to deal with that, because it's in your hand to deal with the dynamic properties. The example here is illustrating the dynamic properties.I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it. If a method is dynamic, we lose the following things: - compile-time type/signature checking - IDE assistance in determining which methods are available - ease of tracing where a method call goes. - not future proof -- for example, if a method name gets changed or moved, the code using the method still compiles. If we lose all these things, there must be *something* we gain by doing this, right? Also, what is the benefit of doing something like this versus specifically calling the dispatcher instead of having the compiler translate it?I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception }The problem is you're dealing with the class which is overloaded its opDot. You know the risk before hand, you are not going to overload for every classes. Here, you seem to little bit overrate this feature. :) If you want things checked, then you probabely need to go back to static. This dynamic stuff is used for dynamic things only, and as long as you have to do it in the dynamic way that means you have no easy way or even impossible to check it at compiletime and you accept the potential risk like the example you posted.Walter already has issues overloading on return type, I'm not sure this is any different. -SteveAlso, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types.Umm, maybe make the compiler to pass the return type into the opDot would allow the opDot func to decide which overload func to call.
Apr 17 2009
在 Fri, 17 Apr 2009 23:27:38 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:On Fri, 17 Apr 2009 11:11:55 -0400, davidl <davidl nospam.org> wrote:But if you want a dynamic property, you won't want to do it in that way. You actually make the opDot to do: void opDot(char[] methodname, ...) { if (methodname = "prop") { // deal with the vararg to get the int x // assign it to _prop, then you're done. // or you can call the prop func here by reconstructing the vararg. } } Notice that if statement can be done by a delegate. Thus when you add a property you simply add your delegate func to the class. And opDot call those delegates one by one.在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:except, you can't define a property like: void prop(int x) { _prop = x ^ ~0; } Using a dynamic method.On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:The opDotExp overload func is supposed to deal with that, because it's in your hand to deal with the dynamic properties. The example here is illustrating the dynamic properties.I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties.Yes, these problems can happen across plugins/host, database design/db apps. Host can't validate its plugins. Host doesn't know what plugins can provide. DB apps which I know don't have much fancy technics to be future proof (what if my db design changes? those SQL won't immediately fail at compile time, only when you run it.)Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it. If a method is dynamic, we lose the following things: - compile-time type/signature checking - IDE assistance in determining which methods are available - ease of tracing where a method call goes. - not future proof -- for example, if a method name gets changed or moved, the code using the method still compiles.I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed: class c { void opDotExp(char[] methodname,...) { if(methodname == "mymethod") callMyMethod(); else throw new Exception("bad method name: " ~ methodname); } } void foo(c myc, bool rarelySetToTrue) { if(rarelySetToTrue) myc.mymethud(); // compiles, will throw runtime exception }The problem is you're dealing with the class which is overloaded its opDot. You know the risk before hand, you are not going to overload for every classes. Here, you seem to little bit overrate this feature. :) If you want things checked, then you probabely need to go back to static. This dynamic stuff is used for dynamic things only, and as long as you have to do it in the dynamic way that means you have no easy way or even impossible to check it at compiletime and you accept the potential risk like the example you posted.If we lose all these things, there must be *something* we gain by doing this, right? Also, what is the benefit of doing something like this versus specifically calling the dispatcher instead of having the compiler translate it?The benefit is you don't need to write the call function, you don't need to write the string quote. Take a look at my other posts about the usecases of this proposal(ddl, ddbi).Actually different, Walter needs to modify the overload mechanism in the current compiler for different function finger prints. What I need to do is sending the return type to the opDot method. Because the overloading is done by the opDot func at runtime, so I don't have Walter's difficulty in dealing with overloading :D -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/Walter already has issues overloading on return type, I'm not sure this is any different. -SteveAlso, how do you overload the return value? Using this proposal, you can't have different dynamic methods that return different types.Umm, maybe make the compiler to pass the return type into the opDot would allow the opDot func to decide which overload func to call.
Apr 17 2009
"davidl" <davidl nospam.org> wrote in message news:op.usje9ia3j5j59l my-tomato...The benefit is you don't need to write the call function,...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?you don't need to write the string quote.I think I'd prefer that. If I put something in quotes, that tells me that typos might not get detected until runtime. But if I don't use quotes, and it compiles, then I know it's ok. With opDotExp, that certainty goes right out the window. All of a sudden I never know if an identifier following a dot compiled because it's ok, or because the error detection has been deferred. I'd feel like I was working in a dynamic language and I *HATE* working with dynamic languages. It's like trying to construct a building on a patch of ground that you know at any moment could change into a lake, sand, cliffside, or simply cease to exist without any warning. Additionally, here's an example from Haxe's xml.Fast: page.node.html.node.head.node.title.x.addChild(Xml.createPCData("Hello")); Think fast without any close inspection: What's the path being used? Umm... Ok, without opDotExp, that would be: page.node("html").node("head").node("title").x.addChild(Xml.createPCData("Hello")); That's a hell of a lot easier to read. Very easy now to see, at a mere glance, the path is "html/head/title". Of course, you could adjust the API for the Haxe/opDotExp version to be more like: page.html.head.title.x.addChild(Xml.createPCData("Hello")); But now (in addition to still not having the certainty of "if an unquoted identifier compiles, it must be ok"), you've opened yourself up to a world of naming collision issues.
Apr 17 2009
On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote:"davidl" <davidl nospam.org> wrote in message news:op.usje9ia3j5j59l my-tomato...This is what I was talking about, but didn't thoroughly explain when I said "ease of tracing where a method call goes." Thanks for explaining this better. I do see usefulness in cases like setting a field in a database row (which should be relatively painless, path-wise). However, my preference is to create a wrapper class around the row to have the compiler to type check my calls. In that case, the typechecked version would just call a dispatch routine anyways (which can be ugly because it's hidden). I think dynamic methods are just asking for trouble in the form of latent bugs. My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher. I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases. When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;) -SteveThe benefit is you don't need to write the call function,...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?you don't need to write the string quote.I think I'd prefer that. If I put something in quotes, that tells me that typos might not get detected until runtime. But if I don't use quotes, and it compiles, then I know it's ok. With opDotExp, that certainty goes right out the window. All of a sudden I never know if an identifier following a dot compiled because it's ok, or because the error detection has been deferred. I'd feel like I was working in a dynamic language and I *HATE* working with dynamic languages. It's like trying to construct a building on a patch of ground that you know at any moment could change into a lake, sand, cliffside, or simply cease to exist without any warning. Additionally, here's an example from Haxe's xml.Fast: page.node.html.node.head.node.title.x.addChild(Xml.createPCData("Hello")); Think fast without any close inspection: What's the path being used? Umm... Ok, without opDotExp, that would be: page.node("html").node("head").node("title").x.addChild(Xml.createPCData("Hello")); That's a hell of a lot easier to read. Very easy now to see, at a mere glance, the path is "html/head/title". Of course, you could adjust the API for the Haxe/opDotExp version to be more like: page.html.head.title.x.addChild(Xml.createPCData("Hello")); But now (in addition to still not having the certainty of "if an unquoted identifier compiles, it must be ok"), you've opened yourself up to a world of naming collision issues.
Apr 17 2009
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.
Apr 17 2009
Nick Sabalausky wrote:"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language. (In fairness, static typing and OO have at best a tense marriage.) But anyway, my point is that it's good to be open-minded. If this conversation does nothing but leave us firmly with our heels in static-land, then we haven't gained anything. If we weren't used to static types we wouldn't be here. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal. I suggested Walter since a long time ago to support opDot!(string). He implemented the useless version (sigh) which was arguably much simpler and offered a cheap way to experiment. So I'm very happy it's back on the table, and with an implementation to boot. Congratulations David. AndreiOn Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.
Apr 17 2009
On Fri, 17 Apr 2009 15:08:12 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Nick Sabalausky wrote:I guess I don't mind the dynamic lookup of methods, but I really don't like the proposal to make it look exactly like a statically typed call. To "hide" the fact that you are doing a dynamic lookup makes me worry about losing the invariants that I come to enjoy with statically typed methods, that is, if I see x.method(a, b, c), it means that the compiler has checked that I called that method correctly with the correctly typed information. really awesome code (things I wish D could do), but I still have to do things like Type[] argTypes = ...; object[] args = ...; x.GetType().GetMethod("myMethod", argTypes).Invoke(x, args); To have that simply cut down to: x.myMethod(a, b, c); is a nifty experiment, but now I lost all ability to know how the compiler is interpreting that. I bet D can do a much better job at runtime type still want to know that I'm dynamically doing something versus statically. Something like: void foo(object x) { x.invoke("myMethod", a, b, c); } where invoke is some method that uses the classinfo of x to look up the method would be freaking awesome ;) -Steve"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language. (In fairness, static typing and OO have at best a tense marriage.) But anyway, my point is that it's good to be open-minded. If this conversation does nothing but leave us firmly with our heels in static-land, then we haven't gained anything. If we weren't used to static types we wouldn't be here. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal. I suggested Walter since a long time ago to support opDot!(string). He implemented the useless version (sigh) which was arguably much simpler and offered a cheap way to experiment. So I'm very happy it's back on the table, and with an implementation to boot. Congratulations David.On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 15:08:12 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote: I guess I don't mind the dynamic lookup of methods, but I really don't like the proposal to make it look exactly like a statically typed call. To "hide" the fact that you are doing a dynamic lookup makes me worry about losing the invariants that I come to enjoy with statically typed methods, that is, if I see x.method(a, b, c), it means that the compiler has checked that I called that method correctly with the correctly typed information.Yah, but that feeling of losing control often marks a paradigm shift (I hate that term, but incidentally it's exactly what I mean here; I guess there is a legit use for it after all). Some people were completely pissed that ++i does not necessarily mean one machine operation, but instead an arbitrary function call. Then STL came and knocked everybody's socks off.really awesome code (things I wish D could do), but I still have to do things like Type[] argTypes = ...; object[] args = ...; x.GetType().GetMethod("myMethod", argTypes).Invoke(x, args); To have that simply cut down to: x.myMethod(a, b, c); is a nifty experiment, but now I lost all ability to know how the compiler is interpreting that. I bet D can do a much better job at powerful, but I still want to know that I'm dynamically doing something versus statically.I don't think you need to worry. Such a style would belong to a handful of types, e.g. Any. It's not a big deal that what you're doing with a value depends on its type.Something like: void foo(object x) { x.invoke("myMethod", a, b, c); } where invoke is some method that uses the classinfo of x to look up the method would be freaking awesome ;)But that doesn't quite unify things. Andrei
Apr 17 2009
在 Sat, 18 Apr 2009 03:26:13 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:On Fri, 17 Apr 2009 15:08:12 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:That's exactly what opDot can be capable of accomplishing. GetMethod is something which feeds the classobject with the method name the opDot woud like to handle and the fingerprint of the function.Nick Sabalausky wrote:I guess I don't mind the dynamic lookup of methods, but I really don't like the proposal to make it look exactly like a statically typed call. To "hide" the fact that you are doing a dynamic lookup makes me worry about losing the invariants that I come to enjoy with statically typed methods, that is, if I see x.method(a, b, c), it means that the compiler has checked that I called that method correctly with the correctly typed information. really awesome code (things I wish D could do), but I still have to do things like Type[] argTypes = ...; object[] args = ...; x.GetType().GetMethod("myMethod", argTypes).Invoke(x, args); To have that simply cut down to: x.myMethod(a, b, c);"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language. (In fairness, static typing and OO have at best a tense marriage.) But anyway, my point is that it's good to be open-minded. If this conversation does nothing but leave us firmly with our heels in static-land, then we haven't gained anything. If we weren't used to static types we wouldn't be here. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal. I suggested Walter since a long time ago to support opDot!(string). He implemented the useless version (sigh) which was arguably much simpler and offered a cheap way to experiment. So I'm very happy it's back on the table, and with an implementation to boot. Congratulations David.On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.is a nifty experiment, but now I lost all ability to know how the compiler is interpreting that. I bet D can do a much better job at powerful, but I still want to know that I'm dynamically doing something versus statically. Something like: void foo(object x) { x.invoke("myMethod", a, b, c); } where invoke is some method that uses the classinfo of x to look up the method would be freaking awesome ;)This can also be done in D2 with my opDot proposal.-Steve-- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 17 2009
Andrei Alexandrescu wrote:Nick Sabalausky wrote:Does that still apply to the template version you proposed?"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.)On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.Reflection is very useful as well. If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language. (In fairness, static typing and OO have at best a tense marriage.)But anyway, my point is that it's good to be open-minded. If this conversation does nothing but leave us firmly with our heels in static-land, then we haven't gained anything. If we weren't used to static types we wouldn't be here. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal. I suggested Walter since a long time ago to support opDot!(string). He implemented the useless version (sigh) which was arguably much simpler and offered a cheap way to experiment. So I'm very happy it's back on the table, and with an implementation to boot. Congratulations David. Andrei
Apr 17 2009
Don wrote:Andrei Alexandrescu wrote:Of course. The template version includes the version that only does dynamic lookup: you can do static, and you can do dynamic. The static part allows you e.g. to optimize some cases if you so wish. With the runtime string you can only do dynamic. Again, making it a template in this case is a win-win thing. There's nothing inferior about it. AndreiI think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.)Does that still apply to the template version you proposed?
Apr 17 2009
Andrei Alexandrescu wrote:Don wrote:I was thinking that, for example, in a DLL, the DLL needs to include a compiled version of each function name it uses; in the non-template version there are no new compiled version. I haven't thought through the implications of this. I guess that it's really no different to foo!("funcname")(args), though. Makes __traits(membersOf) rather interesting -- not necessarily a pure function, might change with time!Andrei Alexandrescu wrote:Of course. The template version includes the version that only does dynamic lookup: you can do static, and you can do dynamic. The static part allows you e.g. to optimize some cases if you so wish. With the runtime string you can only do dynamic.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.)Does that still apply to the template version you proposed?Again, making it a template in this case is a win-win thing. There's nothing inferior about it.I have no doubt it's better for D. I think it's the only option which is viable in a statically-typed language.Andrei
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism: class Foo { void bar() {} } auto foo = new Foo(); traits(foo).func("bar").invoke(); That way, you can have the benefits of runtime-string-identifier-invocation (and have it on *every* class/method), but without completely loosing compile-time checking on the members of every class which is capable of using it.If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language....Doesn't necessarily mean both sides have valid points. Just that there's disagreement. Outside of diplomacy, it doesn't make any sense to agree with something you disagree with, or disagree with something you agree with, just for the sake a closing a rift. Better to just continue debating the issues with logical arguments. If nothing gets accomplished, well ok, fine, but so what? That's a lot better than coming to hasty-but-wrong agreement just for the sake of agreement. I guess what I'm saying is, people coming to an agreement is all fine and dandy, but the most important thing is to arrive at the *correct* agreement. If one group of people insist that "2+2=0" and another group insists that "2+2=10", then it's far better to keep analyzing and debating until "2+2=4" is discovered and proven than to say "let's all be happy!" and hastily agree that "2+2=5". Again, outside of diplomacy, people disagreeing is not the real problem, the real problem is that the best answer either hasn't been found or hasn't been unquestionably shown to be best.
Apr 17 2009
Nick Sabalausky wrote:"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...I was expecting this objection. I think it's not based because unifying syntax is a major part of adding such a feature. If we get to dynamic invocation but we can't go the last mile, we failed. Look at IDispatch-based programming in C++ vs. interpreted languages.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism: class Foo { void bar() {} } auto foo = new Foo(); traits(foo).func("bar").invoke(); That way, you can have the benefits of runtime-string-identifier-invocation (and have it on *every* class/method), but without completely loosing compile-time checking on the members of every class which is capable of using it.Of course. One thing that suggests the righteousness is not necessarily on your side is that plenty knowledgeable, intelligent, credible people use and advocate dynamic typing. Asserting that they simply miss the point is a bit tenuous.If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language....Doesn't necessarily mean both sides have valid points. Just that there's disagreement. Outside of diplomacy, it doesn't make any sense to agree with something you disagree with, or disagree with something you agree with, just for the sake a closing a rift. Better to just continue debating the issues with logical arguments. If nothing gets accomplished, well ok, fine, but so what? That's a lot better than coming to hasty-but-wrong agreement just for the sake of agreement.I guess what I'm saying is, people coming to an agreement is all fine and dandy, but the most important thing is to arrive at the *correct* agreement. If one group of people insist that "2+2=0" and another group insists that "2+2=10", then it's far better to keep analyzing and debating until "2+2=4" is discovered and proven than to say "let's all be happy!" and hastily agree that "2+2=5". Again, outside of diplomacy, people disagreeing is not the real problem, the real problem is that the best answer either hasn't been found or hasn't been unquestionably shown to be best.I'm with you, and in wake of my frequent postings I guess it's pretty known by now that nothing makes me more annoying than knowing 100% I'm right :o). Certainly I'm not one who "agrees to disagree" and I'm glad you aren't either. Andrei
Apr 17 2009
Andrei Alexandrescu wrote:Nick Sabalausky wrote:I'd even say that this feature is 100% syntax sugar. It doesn't add anything we can't do already (in an ugly way)."Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...I was expecting this objection. I think it's not based because unifying syntax is a major part of adding such a feature. If we get to dynamic invocation but we can't go the last mile, we failed. Look at IDispatch-based programming in C++ vs. interpreted languages.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism: class Foo { void bar() {} } auto foo = new Foo(); traits(foo).func("bar").invoke(); That way, you can have the benefits of runtime-string-identifier-invocation (and have it on *every* class/method), but without completely loosing compile-time checking on the members of every class which is capable of using it.
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsamou$204u$1 digitalmars.com...Nick Sabalausky wrote:Can you clarify what you mean here?class Foo { void bar() {} } auto foo = new Foo(); traits(foo).func("bar").invoke(); That way, you can have the benefits of runtime-string-identifier-invocation (and have it on *every* class/method), but without completely loosing compile-time checking on the members of every class which is capable of using it.I was expecting this objection. I think it's not based because unifying syntax is a major part of adding such a feature. If we get to dynamic invocation but we can't go the last mile, we failed. Look at IDispatch-based programming in C++ vs. interpreted languages.No one's infallible no matter how smart or capable (and there's been plenty of examples of supposedy brilliant people doing crazy things like joining wacko cults, etc). I'd be wary of treading so close to [inverse] ad hominem territory. (Besides, aren't there not plenty of "knowledgeable...etc" people on the static-typing side? Like you and Walter? ;) )...Doesn't necessarily mean both sides have valid points. Just that there's disagreement. Outside of diplomacy, it doesn't make any sense to agree with something you disagree with, or disagree with something you agree with, just for the sake a closing a rift. Better to just continue debating the issues with logical arguments. If nothing gets accomplished, well ok, fine, but so what? That's a lot better than coming to hasty-but-wrong agreement just for the sake of agreement.Of course. One thing that suggests the righteousness is not necessarily on your side is that plenty knowledgeable, intelligent, credible people use and advocate dynamic typing. Asserting that they simply miss the point is a bit tenuous.:)I guess what I'm saying is, people coming to an agreement is all fine and dandy, but the most important thing is to arrive at the *correct* agreement. If one group of people insist that "2+2=0" and another group insists that "2+2=10", then it's far better to keep analyzing and debating until "2+2=4" is discovered and proven than to say "let's all be happy!" and hastily agree that "2+2=5". Again, outside of diplomacy, people disagreeing is not the real problem, the real problem is that the best answer either hasn't been found or hasn't been unquestionably shown to be best.I'm with you, and in wake of my frequent postings I guess it's pretty known by now that nothing makes me more annoying than knowing 100% I'm right :o). Certainly I'm not one who "agrees to disagree" and I'm glad you aren't either.
Apr 17 2009
在 Sat, 18 Apr 2009 03:45:43 +0800,Nick Sabalausky <a a.a> 写道:"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...The opDot func can be extremely restrictive by looking up a former added table which are function fingerprints registered by a method call like dynamo.addMethod("myfunc", &myfunc); dynamo.Lenght or dynamo.mymethud would just result runtime exception, because you didn't register these functions.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism:class Foo { void bar() {} } auto foo = new Foo(); traits(foo).func("bar").invoke(); That way, you can have the benefits of runtime-string-identifier-invocation (and have it on *every* class/method), but without completely loosing compile-time checking on the members of every class which is capable of using it.-- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/If anything, this agreed-fest shows that the rift between static typing and dynamic typing is alive and well. I've seen many discussions in which people were mystified how anyone gets anything done in a statically-typed OO language....Doesn't necessarily mean both sides have valid points. Just that there's disagreement. Outside of diplomacy, it doesn't make any sense to agree with something you disagree with, or disagree with something you agree with, just for the sake a closing a rift. Better to just continue debating the issues with logical arguments. If nothing gets accomplished, well ok, fine, but so what? That's a lot better than coming to hasty-but-wrong agreement just for the sake of agreement. I guess what I'm saying is, people coming to an agreement is all fine and dandy, but the most important thing is to arrive at the *correct* agreement. If one group of people insist that "2+2=0" and another group insists that "2+2=10", then it's far better to keep analyzing and debating until "2+2=4" is discovered and proven than to say "let's all be happy!" and hastily agree that "2+2=5". Again, outside of diplomacy, people disagreeing is not the real problem, the real problem is that the best answer either hasn't been found or hasn't been unquestionably shown to be best.
Apr 17 2009
davidl wrote:在 Sat, 18 Apr 2009 03:45:43 +0800,Nick Sabalausky <a a.a> 写道:The problem is a lack of notification at compile time. Runtime exceptions are the problem, not the solution. By the way, if the opDot is a template (per Andrei's suggestion), then if it is marked as nothrow, you have a guarantee that if it compiles, it's valid. nothrow opDot(char [])(args...) doesn't have any of the problems which Nick et. al have mentioned."Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...The opDot func can be extremely restrictive by looking up a former added table which are function fingerprints registered by a method call like dynamo.addMethod("myfunc", &myfunc); dynamo.Lenght or dynamo.mymethud would just result runtime exception, because you didn't register these functions.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism:
Apr 17 2009
"Don" <nospam nospam.com> wrote in message news:gsbovk$nbj$1 digitalmars.com...davidl wrote:Ok, now *that* is something I can be happy with.在 Sat, 18 Apr 2009 03:45:43 +0800,Nick Sabalausky <a a.a> 写道:The problem is a lack of notification at compile time. Runtime exceptions are the problem, not the solution. By the way, if the opDot is a template (per Andrei's suggestion), then if it is marked as nothrow, you have a guarantee that if it compiles, it's valid. nothrow opDot(char [])(args...) doesn't have any of the problems which Nick et. al have mentioned."Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsak2p$1s8a$1 digitalmars.com...The opDot func can be extremely restrictive by looking up a former added table which are function fingerprints registered by a method call like dynamo.addMethod("myfunc", &myfunc); dynamo.Lenght or dynamo.mymethud would just result runtime exception, because you didn't register these functions.I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well. I think D can and should allow string lookup for its methods. It's a low-complexity proposition that adds a very interesting tool to D's arsenal.That's a separate issue. I absolutely agree with the usefulness of being able to invoke static methods via a string identifier at runtime. But I think opDotExp is an extremely flawed way to do it. A much better way would be through a reflection mechanism:
Apr 17 2009
"Nick Sabalausky" <a a.a> wrote in message news:gsbru0$rb6$1 digitalmars.com..."Don" <nospam nospam.com> wrote in message news:gsbovk$nbj$1 digitalmars.com...In fact, now that I think about it, as long as the member name was required to be a template parameter, I'd be perfectly happy with it (and wouldn't even want nothrow to be required). I think that's slightly different from what Andrei's advocated though. Unless I misread something, Andrei, you want it to be possible for the member name to be *either* a template or non-template param, right?The problem is a lack of notification at compile time. Runtime exceptions are the problem, not the solution. By the way, if the opDot is a template (per Andrei's suggestion), then if it is marked as nothrow, you have a guarantee that if it compiles, it's valid. nothrow opDot(char [])(args...) doesn't have any of the problems which Nick et. al have mentioned.Ok, now *that* is something I can be happy with.
Apr 17 2009
Nick Sabalausky wrote:"Nick Sabalausky" <a a.a> wrote in message news:gsbru0$rb6$1 digitalmars.com...I think there's a confusion somewhere. Are you sure you know what you don't like? :o) It's simple, really. First off, there's no way you can pass a variable string as a method name with a regular syntax: string foo = "bar"'; Dynamic d; d.foo(); // passes "foo", not "bar" I hope this clarifies that confusion. If you want to invoke a method known as a string variable, opDot or whatever has nothing to do with it. You don't need any change to the language at all, because you'd write: string foo = "bar"; d.call(foo); // call method bar What opDot does is to allow the regular member syntax while still allowing the callee to look up the name statically or dynamically (assuming the method name is passed into opDot as a template parameter). Note, again, that opDot has everything to do with the syntax and next to nothing to do with the semantics, which is realizable without any change in the language. And that's how the cookie crumbles. I understand you don't like that, but at least we should be clear on where the feature starts and where it ends. Andrei"Don" <nospam nospam.com> wrote in message news:gsbovk$nbj$1 digitalmars.com...In fact, now that I think about it, as long as the member name was required to be a template parameter, I'd be perfectly happy with it (and wouldn't even want nothrow to be required). I think that's slightly different from what Andrei's advocated though. Unless I misread something, Andrei, you want it to be possible for the member name to be *either* a template or non-template param, right?The problem is a lack of notification at compile time. Runtime exceptions are the problem, not the solution. By the way, if the opDot is a template (per Andrei's suggestion), then if it is marked as nothrow, you have a guarantee that if it compiles, it's valid. nothrow opDot(char [])(args...) doesn't have any of the problems which Nick et. al have mentioned.Ok, now *that* is something I can be happy with.
Apr 18 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsbv56$13c2$1 digitalmars.com...I think there's a confusion somewhere. Are you sure you know what you don't like? :o)Over here it's 3:30 in the morning at the moment: I don't know a damn thing about anything right now ;) Least of which being why I'm even bothering to make such a completely pointless post or why I'm sitting here reading posts and complaining about the time instead of just going to bed... But I definitely want to read that over later this afternoon, maybe I'll have some better thoughts about the whole thing at that point. I tried to just now, and it's just random letters to me :) I'm sure it'll make perfect sense this afternoon though.
Apr 18 2009
On 2009-04-18 03:23:21 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:If you want to invoke a method known as a string variable, opDot or whatever has nothing to do with it. You don't need any change to the language at all, because you'd write: string foo = "bar"; d.call(foo); // call method bar What opDot does is to allow the regular member syntax while still allowing the callee to look up the name statically or dynamically (assuming the method name is passed into opDot as a template parameter). Note, again, that opDot has everything to do with the syntax and next to nothing to do with the semantics, which is realizable without any change in the language. And that's how the cookie crumbles. I understand you don't like that, but at least we should be clear on where the feature starts and where it ends.Andrei, I think you, and perhaps everyone here, are overlooking one small but important detail. opDotExp, if a template like you're adovcating, undermines future runtime dynamic call capabilities (which are part of most runtime reflection systems). If you're going to have something such as d.invoke("foo"); available on any type (using some yet-to-see runtime reflection), it will work for a non-template opDotExp (invoke would just forward to opDotExp with the string "foo" if it doesn't find the member through reflection), but it cannot work for an opDotExp template using "foo" as a template argument since string "foo" is a runtime argument. (In fact, I don't see how any template can be callable from runtime reflection.) It ensues that if later we add runtime reflection to D, dynamic calls won't work for template opDotExp. So I'm not really convinced that template is the way to go, even though it would allow great things. Almost all you can do with a template, you already can do by adding members using a mixin. And adding members using a mixin will also work with runtime reflection, unlike templated opDotExp. The only use case left unadressed by mixins and runtime opDotExp is the function with an infinite number of members which want compile time dispatching. Perhaps we need both template and runtime opDotExp... Anyway, I like the general concept so I hope we'll get it, template or not. I just feel the point above has been neglected in the discussion. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 18 2009
Michel Fortin wrote:On 2009-04-18 03:23:21 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string? What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion! And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around! I'm not sure where I'm wrong in explaining this, it looks like I'm unable to remove a very persisting confusion. So let me restate: opDotExp taking a runtime string does not EXPAND your options, it severely LIMITS them. It's very simple: with the former you have strictly LESS options and no NOTHING in terms of added power. It's simple, I swear. AndreiIf you want to invoke a method known as a string variable, opDot or whatever has nothing to do with it. You don't need any change to the language at all, because you'd write: string foo = "bar"; d.call(foo); // call method bar What opDot does is to allow the regular member syntax while still allowing the callee to look up the name statically or dynamically (assuming the method name is passed into opDot as a template parameter). Note, again, that opDot has everything to do with the syntax and next to nothing to do with the semantics, which is realizable without any change in the language. And that's how the cookie crumbles. I understand you don't like that, but at least we should be clear on where the feature starts and where it ends.Andrei, I think you, and perhaps everyone here, are overlooking one small but important detail. opDotExp, if a template like you're adovcating, undermines future runtime dynamic call capabilities (which are part of most runtime reflection systems). If you're going to have something such as d.invoke("foo"); available on any type (using some yet-to-see runtime reflection), it will work for a non-template opDotExp (invoke would just forward to opDotExp with the string "foo" if it doesn't find the member through reflection), but it cannot work for an opDotExp template using "foo" as a template argument since string "foo" is a runtime argument. (In fact, I don't see how any template can be callable from runtime reflection.) It ensues that if later we add runtime reflection to D, dynamic calls won't work for template opDotExp. So I'm not really convinced that template is the way to go, even though it would allow great things. Almost all you can do with a template, you already can do by adding members using a mixin. And adding members using a mixin will also work with runtime reflection, unlike templated opDotExp. The only use case left unadressed by mixins and runtime opDotExp is the function with an infinite number of members which want compile time dispatching. Perhaps we need both template and runtime opDotExp... Anyway, I like the general concept so I hope we'll get it, template or not. I just feel the point above has been neglected in the discussion.
Apr 18 2009
Andrei Alexandrescu wrote:Michel Fortin wrote:A related issue is that obj.opDotExp!"foo"(...) cannot be reflected over because template instantiations aren't part of the typeinfo. Which means if you DO have any methods accessed via opDotExp, you CAN'T invoke them dynamically at runtime, but you COULD if it took a string argument instead of a string template argument. Just sayin' :) -- Daniel... Andrei, I think you, and perhaps everyone here, are overlooking one small but important detail. opDotExp, if a template like you're adovcating, undermines future runtime dynamic call capabilities (which are part of most runtime reflection systems). If you're going to have something such as d.invoke("foo"); available on any type (using some yet-to-see runtime reflection), it will work for a non-template opDotExp (invoke would just forward to opDotExp with the string "foo" if it doesn't find the member through reflection), but it cannot work for an opDotExp template using "foo" as a template argument since string "foo" is a runtime argument. (In fact, I don't see how any template can be callable from runtime reflection.) It ensues that if later we add runtime reflection to D, dynamic calls won't work for template opDotExp. So I'm not really convinced that template is the way to go, even though it would allow great things. Almost all you can do with a template, you already can do by adding members using a mixin. And adding members using a mixin will also work with runtime reflection, unlike templated opDotExp. The only use case left unadressed by mixins and runtime opDotExp is the function with an infinite number of members which want compile time dispatching. Perhaps we need both template and runtime opDotExp... Anyway, I like the general concept so I hope we'll get it, template or not. I just feel the point above has been neglected in the discussion.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string? What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion! And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around! I'm not sure where I'm wrong in explaining this, it looks like I'm unable to remove a very persisting confusion. So let me restate: opDotExp taking a runtime string does not EXPAND your options, it severely LIMITS them. It's very simple: with the former you have strictly LESS options and no NOTHING in terms of added power. It's simple, I swear. Andrei
Apr 18 2009
在 Sun, 19 Apr 2009 03:15:02 +0800,Daniel Keep <daniel.keep.lists gmail.com> 写道:Andrei Alexandrescu wrote:Umm, actually you can... but with bad duplication in code: void Invoke(methodname, ...) { if (methodname = "compile_time_dispatched_method") // these sort of comparison exists in template opDot in a static manner. { opDot("compile_time_dispatched_method")(args); } } Yes, we get duplication here. I don't have an idea to solve the duplication elegantly yet. Maybe string mixins?Michel Fortin wrote:A related issue is that obj.opDotExp!"foo"(...) cannot be reflected over because template instantiations aren't part of the typeinfo. Which means if you DO have any methods accessed via opDotExp, you CAN'T invoke them dynamically at runtime, but you COULD if it took a string argument instead of a string template argument.... Andrei, I think you, and perhaps everyone here, are overlooking one small but important detail. opDotExp, if a template like you're adovcating, undermines future runtime dynamic call capabilities (which are part of most runtime reflection systems). If you're going to have something such as d.invoke("foo"); available on any type (using some yet-to-see runtime reflection), it will work for a non-template opDotExp (invoke would just forward to opDotExp with the string "foo" if it doesn't find the member through reflection), but it cannot work for an opDotExp template using "foo" as a template argument since string "foo" is a runtime argument. (In fact, I don't see how any template can be callable from runtime reflection.) It ensues that if later we add runtime reflection to D, dynamic calls won't work for template opDotExp. So I'm not really convinced that template is the way to go, even though it would allow great things. Almost all you can do with a template, you already can do by adding members using a mixin. And adding members using a mixin will also work with runtime reflection, unlike templated opDotExp. The only use case left unadressed by mixins and runtime opDotExp is the function with an infinite number of members which want compile time dispatching. Perhaps we need both template and runtime opDotExp... Anyway, I like the general concept so I hope we'll get it, template or not. I just feel the point above has been neglected in the discussion.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string? What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion! And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around! I'm not sure where I'm wrong in explaining this, it looks like I'm unable to remove a very persisting confusion. So let me restate: opDotExp taking a runtime string does not EXPAND your options, it severely LIMITS them. It's very simple: with the former you have strictly LESS options and no NOTHING in terms of added power. It's simple, I swear. AndreiJust sayin' :) -- Daniel-- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 18 2009
davidl wrote:鍦 Sun, 19 Apr 2009 03:15:02 +0800锛孌aniel Keep <daniel.keep.lists gmail.com> 鍐欓亾:What you want is: void opDot(string name, T...)(T args) { invoke(name, variantArray(args)); } void invoke(string name, Variant[] args) { ... } So it's precisely the other way around. I agree you _could_ call things the other way, but it goes against the natural way. AndreiAndrei Alexandrescu wrote:Umm, actually you can... but with bad duplication in code: void Invoke(methodname, ...) { if (methodname = "compile_time_dispatched_method") // these sort of comparison exists in template opDot in a static manner. { opDot("compile_time_dispatched_method")(args); } } Yes, we get duplication here. I don't have an idea to solve the duplication elegantly yet. Maybe string mixins?Michel Fortin wrote:A related issue is that obj.opDotExp!"foo"(...) cannot be reflected over because template instantiations aren't part of the typeinfo. Which means if you DO have any methods accessed via opDotExp, you CAN'T invoke them dynamically at runtime, but you COULD if it took a string argument instead of a string template argument.... Andrei, I think you, and perhaps everyone here, are overlooking one small but important detail. opDotExp, if a template like you're adovcating, undermines future runtime dynamic call capabilities (which are part of most runtime reflection systems). If you're going to have something such as d.invoke("foo"); available on any type (using some yet-to-see runtime reflection), it will work for a non-template opDotExp (invoke would just forward to opDotExp with the string "foo" if it doesn't find the member through reflection), but it cannot work for an opDotExp template using "foo" as a template argument since string "foo" is a runtime argument. (In fact, I don't see how any template can be callable from runtime reflection.) It ensues that if later we add runtime reflection to D, dynamic calls won't work for template opDotExp. So I'm not really convinced that template is the way to go, even though it would allow great things. Almost all you can do with a template, you already can do by adding members using a mixin. And adding members using a mixin will also work with runtime reflection, unlike templated opDotExp. The only use case left unadressed by mixins and runtime opDotExp is the function with an infinite number of members which want compile time dispatching. Perhaps we need both template and runtime opDotExp... Anyway, I like the general concept so I hope we'll get it, template or not. I just feel the point above has been neglected in the discussion.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string? What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion! And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around! I'm not sure where I'm wrong in explaining this, it looks like I'm unable to remove a very persisting confusion. So let me restate: opDotExp taking a runtime string does not EXPAND your options, it severely LIMITS them. It's very simple: with the former you have strictly LESS options and no NOTHING in terms of added power. It's simple, I swear. AndreiJust sayin' :)
Apr 18 2009
On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are. When writing in D and interacting with a scripting language, or remote objects, you can write a function call that will use opDotExp to forward the call to the script object. A template fulfill this goal pretty well. You may want the reverse too: call a D function from a script, or a remote machine, via some runtime reflection mecanism. That's where we have a problem: if the script calls function "foo", and the object implements function "foo" using opDotExp (because the object is itself a proxy to something else for instance), then it just won't work. Also, if, for example, you use a templated opDotExp to implement a bunch of related methods (like those "xyzw", "xwyz", etc.), then you're making those inaccessible from reflection. If on the other hand you do the same using a mixin adding true members to your class or struct, then the compiler can include them in the reflection data, and they'll be accessible to the outside world. So, a runtime opDotExp is superior for some use cases because it works for function calls comming from the outside (via runtime or compile-time reflection), and you may need that if you want to expose some D code via reflection. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 18 2009
在 Sun, 19 Apr 2009 03:42:02 +0800,Michel Fortin <michel.fortin michelf.com> 写道:On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Umm, right, you hunt the problem I didn't consider before. But in that case, actually you are trying to use a static info based runtime reflection to deal with a dynamic D object. Just like you try to deal with a dynamic object with previous introspection of it. I think for runtime reflection against a dynamic object, the only way is querying the object itself. And the object returns the runtime info back.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are. When writing in D and interacting with a scripting language, or remote objects, you can write a function call that will use opDotExp to forward the call to the script object. A template fulfill this goal pretty well. You may want the reverse too: call a D function from a script, or a remote machine, via some runtime reflection mecanism. That's where we have a problem: if the script calls function "foo", and the object implements function "foo" using opDotExp (because the object is itself a proxy to something else for instance), then it just won't work.Also, if, for example, you use a templated opDotExp to implement a bunch of related methods (like those "xyzw", "xwyz", etc.), then you're making those inaccessible from reflection. If on the other hand you do the same using a mixin adding true members to your class or struct, then the compiler can include them in the reflection data, and they'll be accessible to the outside world. So, a runtime opDotExp is superior for some use cases because it works for function calls comming from the outside (via runtime or compile-time reflection), and you may need that if you want to expose some D code via reflection.-- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 18 2009
Michel Fortin wrote:On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:That's a very clear description. Is the syntax sugar as important in that direction? I mean, this proposal doesn't make any difference other than to syntax sugar. You can already have b = a.swizzle!("xwyz"); with the exact problems you mention. So it's not as if templated opDotExp creates new problems for function calls from the outside; it just doesn't solve the existing ones. It seems pretty clear that dynamic programming languages and template value arguments don't get on well at all.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are. When writing in D and interacting with a scripting language, or remote objects, you can write a function call that will use opDotExp to forward the call to the script object. A template fulfill this goal pretty well. You may want the reverse too: call a D function from a script, or a remote machine, via some runtime reflection mecanism. That's where we have a problem: if the script calls function "foo", and the object implements function "foo" using opDotExp (because the object is itself a proxy to something else for instance), then it just won't work. Also, if, for example, you use a templated opDotExp to implement a bunch of related methods (like those "xyzw", "xwyz", etc.), then you're making those inaccessible from reflection. If on the other hand you do the same using a mixin adding true members to your class or struct, then the compiler can include them in the reflection data, and they'll be accessible to the outside world. So, a runtime opDotExp is superior for some use cases because it works for function calls comming from the outside (via runtime or compile-time reflection), and you may need that if you want to expose some D code via reflection.
Apr 18 2009
Michel Fortin wrote:On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Wrong. It's impossible to pass a dynamic string as a static string, so the street is one way. AndreiI'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are.
Apr 18 2009
On 2009-04-18 17:48:33 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Michel Fortin wrote:Indeed it's impossible using a template which requires a static string. And that's exactly the problem: some times you're supposed to make it work both ways, as I've explained in the rest of my post you've cut down. Did you read it? I won't repeat everything, but here's the important part: not having it go both ways *is* an important drawback. And it doesn't go both ways only if opDotExp is a template. -- Michel Fortin michel.fortin michelf.com http://michelf.com/On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Wrong. It's impossible to pass a dynamic string as a static string, so the street is one way.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are.
Apr 18 2009
Michel Fortin wrote:On 2009-04-18 17:48:33 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread. You say: well if opDot were a template then a scripting language can't get to it because what it has is a dynamic string. Yes. That's why opDot does whatever static string processing and then forwards, if the design asks for it, to the dynamic function. opDot's participation is solely a syntax helper within D. AndreiMichel Fortin wrote:Indeed it's impossible using a template which requires a static string. And that's exactly the problem: some times you're supposed to make it work both ways, as I've explained in the rest of my post you've cut down. Did you read it? I won't repeat everything, but here's the important part: not having it go both ways *is* an important drawback. And it doesn't go both ways only if opDotExp is a template.On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Wrong. It's impossible to pass a dynamic string as a static string, so the street is one way.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are.
Apr 18 2009
On 2009-04-18 22:21:50 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:I did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread.Then let's try to remove some of that confusion.You say: well if opDot were a template then a scripting language can't get to it because what it has is a dynamic string. Yes. That's why opDot does whatever static string processing and then forwards, if the design asks for it, to the dynamic function. opDot's participation is solely a syntax helper within D.Yes, I understand that template opDot as you proposed is just a syntax helper. I'm arguing that many uses proposed for this syntax helper are better implemented by mixins (because functions added by mixin are accessible using reflection, while functions added by a templated syntax helper are not). Of the remaining uses that can't be served by mixins, most need runtime dispatch, which can be made compatible with a runtime-dispatch system if there is a standard name for a non-template catch-all function (as opposed to a user-defined name you can only know from within a template opDot). And the remaining ones that require a template opDot are not really useful (case-insentiveness?). That was the summary. Following is the detailed explanation. Now, Andrei, if you think something doesn't make any sense in all this, please tell me where it stops making sense so I can understand were we're disagreeing. Let's consider how runtime reflection works. Basically, you have a list of available functions for a given type, and their function pointers. When you want to invoke a function using runtime reflection, you find it in the list, and call the pointer. Something like this (simplified) function: void invokeViaReflection(string name) { void function()* fptr = name in functionList; if (fptr) ftpr(); else throw Exception("Function "~ name ~" not found."); } (Note that you can already this kind of reflection by building the list at compile time for the types you want with something like ClassInfoEx, but this could also be built into the compiler.) So if you have an external script that wants to call a D function, or you receive a remote invocation via network, the script will call that invokeViaReflection function above which will call the right function. Now, let's say we want to add the ability for a D class to act as a proxy for another object, then we need to catch calls to undefined functions and do something with them (most likely forward them to someone else). For that to be reflected to the script, we'll have to modify the invokeViaReflection like this: void invokeViaReflection(string name) { void function()* fptr = name in functionList; if (fptr) ftpr(); else { void function(string name)* catchAll = "catchAllHandlerFunc" in functionList; if (catchAll) catchAll(name); else throw Exception("Function "~ name ~" not found."); } } The thing is that the name of that "catchAllHandlerFunc" function needs to be standardised for it to work with runtime reflection. If the standardized way of doing this is to implement things in a template and from that template call a catch-all function with a user-defined, unpredictable name, then we can't use the catch-all function at all with runtime reflection since the name of that runtime catch-all function is burried in a template. This was my first point. I hope it makes sense and that we agree about the conclusion: there needs to be a standardized name for a non-template catch-all function if we want runtime reflection to reflect the compile-time dispatching process. (By the way this, in itself doesn't preclude having a template catch-all too, only if there is one the runtime one should be standardized too.) Now, for my second point, let's consider some use cases for a catch-all mecanism. Let's look at the swizzle case. You want a class or a struct with a function for every permutation of "xwyz". Beside doing that manually, here's what you can do: Solution A: use a mixin. This will add 256 functions to your struct, and those functions will appear in the functionList used by invokeViaReflection. Solution B.1: use a templated catch-all function, and use the name to instanciate the catch-all. Calling the function will work at compile time, but at runtime invokeViaReflection is left in the dust. Solution B.2: in addition to the templated catch-all function in B.1, add a runtime catch-all. This is about twice the work, but invokeViaReflection can work with those functions. So of all the solutions above, B.2 is twice the work and adds the risk of the two implementations becoming out of sync, and is probably slower than A when called through invokeViaReflection. B.1 breaks invokeViaReflection. And A works for everything. My conclusion is that solution A is preferable. And I think the language should encourage the use of solution A in this case. Now, let's look at the proxy case, where you want to forward function calls to another object. In fact, there are two variant of this case: one where you know the type at compile-time, one where you don't (you only know the base class) but still want to forward all calls. Solution A: use a mixin. The mixin will create a wrapper function for all functions in the wrapped object it can find using compile-time reflection, and those functions will appear in the functionList used by invokeViaReflection. Solution B.1: use a templated catch-all function which will simply issue a call on the wrapped object. Calling the function will work at compile time, but at runtime invokeViaReflection is left in the dust if we try to use it on our proxy. Solution B.2: in addition to the templated catch-all function in B.2, add a runtime catch-all that will check the runtime string against the function names obtained at compile time and call the right function. This is more than twice the work, but invokeViaReflection can call functions on our proxy. Solution C: create a runtime catch-all function that will use invokeViaReflection to call the right function on the wrapped object. Note that solution C is the only option if you don't know the exact type at compile-time, like when you only know the base class. Unfortunately, solution C for our proxy won't work if the wrapped object uses B.1. Same for solution A, which relies on compile-time reflection. So that's why I think B.1 (templated catch-all function) should be avoided whenever a mixin solution is possible. In the two use cases above, you can use a mixin and get the same "staticness" as in B, but the mixin solution also offer support for reflection, which makes it superior for the cases you're stuck using the object at runtime, or when we want to introspect at compile-time. And when a mixin doesn't cut it, the template will most likely just be a stub for calling a runtime mecanism. Note that I'm not that much against a templated opDot, I just want to point out its drawbacks for reflection. I'm also unconvinced of its usefulness considering you can do the same things better using mixins leaving only the runtime case to be solved, where you are better served without a template anyway. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 19 2009
Michel Fortin wrote:The thing is that the name of that "catchAllHandlerFunc" function needs to be standardised for it to work with runtime reflection.I agree with this wholeheartedly. However, opDotExp would be hamstringed if it were made to serve this function. Since classes can implement interfaces, you could expose an interface IDispatch or the like. This doesn't suffice for structs, though.Let's look at the swizzle case. You want a class or a struct with a function for every permutation of "xwyz". Beside doing that manually, here's what you can do: Solution A: use a mixin. This will add 256 functions to your struct, and those functions will appear in the functionList used by invokeViaReflection. Solution B.1: use a templated catch-all function, and use the name to instanciate the catch-all. Calling the function will work at compile time, but at runtime invokeViaReflection is left in the dust. Solution B.2: in addition to the templated catch-all function in B.1, add a runtime catch-all. This is about twice the work, but invokeViaReflection can work with those functions.The standard form will be something like: class Dispatch : IDispatch { auto opDotExp(string name)(...) { return dispatch(name, _arguments, _argptr); } auto dispatch(string name, ...) { // do stuff } } This isn't much added work.Now, let's look at the proxy case, where you want to forward function calls to another object. In fact, there are two variant of this case: one where you know the type at compile-time, one where you don't (you only know the base class) but still want to forward all calls. Solution A: use a mixin. The mixin will create a wrapper function for all functions in the wrapped object it can find using compile-time reflection, and those functions will appear in the functionList used by invokeViaReflection.That's a lot of work, but it can get you a performance increase in the case where you know something about the class at compile time (for instance, you have an object that implements a particular interface, but you want to call non-interface functions via the wrapper). Of course, you could manually forward methods as well and get the same performance increase. But that would be more difficult to write.Note that I'm not that much against a templated opDot, I just want to point out its drawbacks for reflection. I'm also unconvinced of its usefulness considering you can do the same things better using mixins leaving only the runtime case to be solved, where you are better served without a template anyway.Well, you can do the same things with some other advantages with mixins, but it's harder to write. I think the appropriate solution is to add a solver to the compiler that can determine valid inputs for opDotExp and, if that set is below a threshold, unroll the template into regular member functions. Or, you know, just implement a static foreach that you can use in templates. And anything else that we can think of that's reasonable to make the mixin solution easier to work with. If that's accomplished, there'd be no reason to have opDotExp as a template.
Apr 19 2009
Michel Fortin wrote:On 2009-04-18 22:21:50 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Thanks for doing so. Given that my wits are spent with regard to this thread, I am replying out of respect for the considerable effort you have put in writing an explanation. I agree that method names swallowed by opDotExp will not be exposed to any reflection mechanism and that that can be a drawback. But sometimes you don't even want to exhaustively generate all method names. In the Pascalize example, you wouldn't want to generate all case combinations of your methods. Also in the swizzle example, maybe you don't want to compulsively expose all of the xyzw combinations. You completely lost me about the necessity of a standardized catch-all function. My view is that if you want to forward to someone else, you just call the runtime invoke() for the guy you want to forward to. So I see exactly zero need for a standardized catch-all, and a red herring in the discussion about the syntactic help brought about by opDotExp. Given the size of your latest effort to explain things, I guess it would be out of place for me to ask for further explanation. Also, when a thread becomes an exchange between two people, it's a clear sign that that thread should be put to rest. I'm still a bit dumbfounded that such a minor issue has caused so much aggravation, but I guess odder things have happened on the Usenet. AndreiI did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread.Then let's try to remove some of that confusion.
Apr 19 2009
Andrei Alexandrescu wrote:Michel Fortin wrote:The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents. I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.On 2009-04-18 22:21:50 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Thanks for doing so. Given that my wits are spent with regard to this thread, I am replying out of respect for the considerable effort you have put in writing an explanation. I agree that method names swallowed by opDotExp will not be exposed to any reflection mechanism and that that can be a drawback. But sometimes you don't even want to exhaustively generate all method names. In the Pascalize example, you wouldn't want to generate all case combinations of your methods. Also in the swizzle example, maybe you don't want to compulsively expose all of the xyzw combinations. You completely lost me about the necessity of a standardized catch-all function. My view is that if you want to forward to someone else, you just call the runtime invoke() for the guy you want to forward to. So I see exactly zero need for a standardized catch-all, and a red herring in the discussion about the syntactic help brought about by opDotExp.I did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread.Then let's try to remove some of that confusion.
Apr 19 2009
Christopher Wright wrote:Andrei Alexandrescu wrote:Oddly enough, I got it now :o). AndreiMichel Fortin wrote:The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents. I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.On 2009-04-18 22:21:50 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Thanks for doing so. Given that my wits are spent with regard to this thread, I am replying out of respect for the considerable effort you have put in writing an explanation. I agree that method names swallowed by opDotExp will not be exposed to any reflection mechanism and that that can be a drawback. But sometimes you don't even want to exhaustively generate all method names. In the Pascalize example, you wouldn't want to generate all case combinations of your methods. Also in the swizzle example, maybe you don't want to compulsively expose all of the xyzw combinations. You completely lost me about the necessity of a standardized catch-all function. My view is that if you want to forward to someone else, you just call the runtime invoke() for the guy you want to forward to. So I see exactly zero need for a standardized catch-all, and a red herring in the discussion about the syntactic help brought about by opDotExp.I did, but sorry, it doesn't make sense and does nothing but continue the terrible confusion going in this thread.Then let's try to remove some of that confusion.
Apr 19 2009
Andrei Alexandrescu wrote:Christopher Wright wrote:Thanks Cristopher. :-) Another interesting use of this, beside integration with scripting languages, would be to replicate the concept of distributed objects in Cocoa. <http://developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/DistrObjects/Concepts/architecture.html> -- Michel Fortin michel.fortin michelf.com http://michelf.com/Andrei Alexandrescu wrote:Oddly enough, I got it now :o).You completely lost me about the necessity of a standardized catch-all function. My view is that if you want to forward to someone else, you just call the runtime invoke() for the guy you want to forward to. So I see exactly zero need for a standardized catch-all, and a red herring in the discussion about the syntactic help brought about by opDotExp.The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents. I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.
Apr 19 2009
Hello Christopher,The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents.So it is being argued that there should be a standard way to do a run time function invocation system? I'll buy that.I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.Maybe there should be.
Apr 19 2009
BCS wrote:Hello Christopher,But there isn't, so this is YAGNI. And if there were, then this particular issue would immediately be solved.The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents.So it is being argued that there should be a standard way to do a run time function invocation system? I'll buy that.I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.Maybe there should be.
Apr 20 2009
On 2009-04-20 07:25:43 -0400, Christopher Wright <dhasenan gmail.com> said:BCS wrote:The thing is that with compile-time reflection you can already build your own runtime-reflection system (with some limitations). -- Michel Fortin michel.fortin michelf.com http://michelf.com/Hello Christopher,But there isn't, so this is YAGNI. And if there were, then this particular issue would immediately be solved.The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents.So it is being argued that there should be a standard way to do a run time function invocation system? I'll buy that.I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.Maybe there should be.
Apr 20 2009
Michel Fortin wrote:On 2009-04-20 07:25:43 -0400, Christopher Wright <dhasenan gmail.com> said:You're telling me? http://felt-project.org/reflect/trunkBCS wrote:The thing is that with compile-time reflection you can already build your own runtime-reflection system (with some limitations).Hello Christopher,But there isn't, so this is YAGNI. And if there were, then this particular issue would immediately be solved.The utility is when you are looking for methods to invoke via runtime reflection, you can determine that a given function is one of these runtime opDotExp equivalents.So it is being argued that there should be a standard way to do a run time function invocation system? I'll buy that.I don't know how useful this is, in point of fact. Unless there's a standard system in D for integrating with scripting languages, anyway.Maybe there should be.
Apr 20 2009
Hello Michel,On 2009-04-18 17:48:33 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:If opDotExp is a template you can do: struct S { void NonStaticVersion(char[] name, args...) { ...} void opDotExp(char[] name, T...)(T t) { NonStaticVersion(name, t); } } if it is not a tamplate: struct S { void StaticVersion(char[] name, T ... )(T t) { ...} void opDotExp(char[] name, T...) { StaticVersion!( /******** what goes here?? *********/ )(T); } } you are either wrong, arguing something completely different than what everyone thinks you are or figured out how to do something everyone else thinks is impossible.Michel Fortin wrote:Indeed it's impossible using a template which requires a static string. And that's exactly the problem: some times you're supposed to make it work both ways, as I've explained in the rest of my post you've cut down. Did you read it? I won't repeat everything, but here's the important part: not having it go both ways *is* an important drawback. And it doesn't go both ways only if opDotExp is a template.On 2009-04-18 11:19:38 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Wrong. It's impossible to pass a dynamic string as a static string, so the street is one way.I'm confused. Isn't it clear that at the moment we "have" the ability to pass a function name as a runtime string?Indeed, you can pass the template argument as a runtime argument to another function. No misunderstanding here.What we're lacking is the ability to implement that using reflection, but that's an entirely separated discussion!Runtime reflection lacking indeed, but wether runtime reflection is an entirely separated discussion depends on if what we're doing will get in the way of implementing it.And no, you're not supposed to forward from invoke(string, Variant[]...) to opDotExp - it's precisely the other way around!Wrong. Whether it's one way or another entirely depends on what your goals are.
Apr 18 2009
Andrei Alexandrescu wrote:I think there's merit in binding via strings. It makes for very flexible code that is future-proof, dynamic-linking-friendly, and hot-swappable without recompiling (e.g. you don't need to recompile because you now implement an interface etc.) Reflection is very useful as well.I don't think you can implement an interface with opDotExp, since it has a different signature.
Apr 17 2009
Nick Sabalausky wrote:"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjnzajzeav7ka steves.networkengines.com...That's the VB/PHP nightmare -- allow any garbage to compile. Yet, if the function name is in a template (which I believe it has to be), the problem isn't as bad: you can detect it in many cases. The only use case I can really see for this is when an extremely large number of functions need to be created. Swizzling an array was one example that was mentioned previously: float4 f, g; g = f.wzyx * f.zzxy; If you were to create all possibilities, it's 4^4 = 256 function overloads. Which is too many to document, but is still feasible to create with a mixin. If it was instead 8^8 functions, it'd really be a lot easier on the poor compiler's symbol table to have the functions generated only on demand. Still, g = f.swizzle!("wzyx"); (or Andrei-style g = f.swizzle!"wzyx"; ) isn't so terrible. D is already incredibly more flexible and powerful than (say) C++, so there's not going to be any use cases which go from terrible to perfect.On Fri, 17 Apr 2009 14:32:07 -0400, Nick Sabalausky <a a.a> wrote: My main concern that I've read so far is how if a class has a dynamic method dispatcher that's callable like a method, you can't rely on the compiler to help you typecheck (or spellcheck) the *non-dynamic* methods, because it will just default to sending incorrectly typed data or misspelled methods to the dynamic dispatcher.That is a *very* good point, that hadn't even occured to me.If there were a few use cases which were sufficiently important, it might be possible to create a solution for them which didn't allow so much undesirable behaviour.I think dynamic methods have a very limited use, and probably aren't worth polluting the D language for a few rare cases.Agreed.Yeah, The ideal language would detect ALL bugs at compile time. We don't want to move in the wrong direction.When you know the API ahead of time, you're almost always better off to have statically typed objects. When you don't know it ahead of time, well, I prefer the uglyness of seeing the quoted strings to having the compiler just start trusting everything I do ;)Agreed.
Apr 17 2009
On Fri, 17 Apr 2009 23:23:52 +0400, Don <nospam nospam.com> wrote:Yeah, The ideal language would detect ALL bugs at compile time. We don't want to move in the wrong direction.I would consider it a "wrong direction". You won't use it *that* frequent, only in those places where it trully fits. For example, a Variant class and scripting languages bindings would greatly benefit for having this functionality.
Apr 17 2009
On Fri, 17 Apr 2009 23:36:06 +0400, Denis Koroskin <2korden gmail.com> wrote:On Fri, 17 Apr 2009 23:23:52 +0400, Don <nospam nospam.com> wrote:Err.. Should read: I woudn't consider it a "wrong direction".Yeah, The ideal language would detect ALL bugs at compile time. We don't want to move in the wrong direction.I would consider it a "wrong direction".
Apr 17 2009
Denis Koroskin wrote:On Fri, 17 Apr 2009 23:23:52 +0400, Don <nospam nospam.com> wrote:Yah, for example Variant could define opDotExp to look whether the currently stored type supports the name. With the appropriate compile-time introspection it could make that quite fast too. Pretty awesome if you ask me. I'm very excited about this. AndreiYeah, The ideal language would detect ALL bugs at compile time. We don't want to move in the wrong direction.I would consider it a "wrong direction". You won't use it *that* frequent, only in those places where it trully fits. For example, a Variant class and scripting languages bindings would greatly benefit for having this functionality.
Apr 17 2009
Nick Sabalausky wrote:"davidl" <davidl nospam.org> wrote in message news:op.usje9ia3j5j59l my-tomato...It's more work, but it lets you do other interesting things. Prime example is one I mentioned earlier. Let's say we also get full RTTI implemented soon (either in a library [I'm working on it] or in the compiler). Then you can write a Variant type that you can call arbitrary methods on. Neat, huh? Let's say you integrate D with a scripting language where you can add methods to an object at arbitrary times. Instead of writing: scriptObj.invokeMethod("methodname", arguments); You can instead write: scriptObj.methodname(arguments); This is a library type which has no business knowing about any methods that you have defined on scriptObj. Moreover, the alternative is to write this: template ScriptMethod(string name) { enum ScriptMethod = "void " ~ name ~ "(...) { return _vm.invokeMethod(_obj, \"" ~ name ~ \"" ~, _arguments, _argptr); }"; } class ScriptObjWrapper { // repeat this a few dozen times for each method mixin (ScriptMethod!("methodname")); } It's syntactic sugar, but it's really neat.The benefit is you don't need to write the call function,...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?
Apr 17 2009
"Christopher Wright" <dhasenan gmail.com> wrote in message news:gsaver$2ini$1 digitalmars.com...Nick Sabalausky wrote:Brainfuck and AppleScript are really neat, but I wouldn't want to write an app in either of them ;) But anyway, like I've said before, syntactic sugar is fine, but this is syntactic sugar that undermines the programmer's ability to rely on compile-time checking of class members. "But only for the classes that use it." No, it undermines that trust across the board because it's non-obvious what classes are using it, so you'd have to always be on guard. "Operator overloading blah blah blah" That only causes problems when it's used *and* abused by a class, while this would cause problems *any* time it's used. Etc etc..."davidl" <davidl nospam.org> wrote in message news:op.usje9ia3j5j59l my-tomato...It's more work, but it lets you do other interesting things. Prime example is one I mentioned earlier. Let's say we also get full RTTI implemented soon (either in a library [I'm working on it] or in the compiler). Then you can write a Variant type that you can call arbitrary methods on. Neat, huh? Let's say you integrate D with a scripting language where you can add methods to an object at arbitrary times. Instead of writing: scriptObj.invokeMethod("methodname", arguments); You can instead write: scriptObj.methodname(arguments); This is a library type which has no business knowing about any methods that you have defined on scriptObj. Moreover, the alternative is to write this: template ScriptMethod(string name) { enum ScriptMethod = "void " ~ name ~ "(...) { return _vm.invokeMethod(_obj, \"" ~ name ~ \"" ~, _arguments, _argptr); }"; } class ScriptObjWrapper { // repeat this a few dozen times for each method mixin (ScriptMethod!("methodname")); } It's syntactic sugar, but it's really neat.The benefit is you don't need to write the call function,...But you do have to write the opDotExp() function. How is that less work than just writing a dispatch function?
Apr 17 2009
Nick Sabalausky wrote:But anyway, like I've said before, syntactic sugar is fine, but this is syntactic sugar that undermines the programmer's ability to rely on compile-time checking of class members. "But only for the classes that use it." No, it undermines that trust across the board because it's non-obvious what classes are using it, so you'd have to always be on guard. "Operator overloading blah blah blah" That only causes problems when it's used *and* abused by a class, while this would cause problems *any* time it's used. Etc etc...Compile time checking is not undermined at all, even for classes that use this functionality. opDotExp just makes it easier to create classes with a large, possibly infinite set of members. There are three possible cases: 1. The class does not use opDotExp. Compile time member checking is not undermined. 2. The body of opDotExp triggers an error at compile time if it receives an unexpected name. Compile time member checking is not undermined, although the specific error message may have changed. 3. The body of opDotExp accepts all names. Compile time member checking is not undermined, we just have a class that has every legal identifier as a member. -- Rainer Deyke - rainerd eldwood.com
Apr 17 2009
"Rainer Deyke" <rainerd eldwood.com> wrote in message news:gsbodm$mjc$1 digitalmars.com...Nick Sabalausky wrote:If the member-name parameter to opDotExp was *required* to be a template paramater, then I agree, and I would have no objections to having that. But it should be pointed out that that would not actually be dynamic invokation, since you wouldn't be able to invoke a member whose name is only known at run-time. (But I would love for that to be possible through a reflection API.)But anyway, like I've said before, syntactic sugar is fine, but this is syntactic sugar that undermines the programmer's ability to rely on compile-time checking of class members. "But only for the classes that use it." No, it undermines that trust across the board because it's non-obvious what classes are using it, so you'd have to always be on guard. "Operator overloading blah blah blah" That only causes problems when it's used *and* abused by a class, while this would cause problems *any* time it's used. Etc etc...Compile time checking is not undermined at all, even for classes that use this functionality. opDotExp just makes it easier to create classes with a large, possibly infinite set of members. There are three possible cases: 1. The class does not use opDotExp. Compile time member checking is not undermined. 2. The body of opDotExp triggers an error at compile time if it receives an unexpected name. Compile time member checking is not undermined, although the specific error message may have changed. 3. The body of opDotExp accepts all names. Compile time member checking is not undermined, we just have a class that has every legal identifier as a member.
Apr 17 2009
Nick Sabalausky wrote:If the member-name parameter to opDotExp was *required* to be a template paramater, then I agree, and I would have no objections to having that. But it should be pointed out that that would not actually be dynamic invokation, since you wouldn't be able to invoke a member whose name is only known at run-time. (But I would love for that to be possible through a reflection API.)As we can all clearly see, in obj.someDynamicFunction( "Foo!" ); "someDynamicFunction" is definately known at compile-time, and not something you could change at runtime. Thus, making the member name parameter a template parameter seems the most logical solution. The fact you can't invoke arbitrary members chosen at runtime with it has little to do with opDotExp and much to do with how the D language is. If you want true dynamic invocation you need a separate function anyway, or you'd end up with code like this: string s = "someDynamicFunction"; obj.opDotExp( s ); Now, you could simply alias "opDotExp" to "invoke" or whatever you please, but having invoke be a separate function does not seem like a horrible trade-off to me. -- Simen
Apr 18 2009
Op Sat, 18 Apr 2009 00:22:25 +0200 schreef Christopher Wright <dhasenan gmail.com>:Let's say you integrate D with a scripting language where you can add methods to an object at arbitrary times. Instead of writing: scriptObj.invokeMethod("methodname", arguments);I thought that would be the obvious application, and decided to mention the haXe instead :-) Guess it's only obvious for someone used to dynamic languages...
Apr 18 2009
Steven Schveighoffer wrote:Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it. If a method is dynamic, we lose the following things: - compile-time type/signature checking - IDE assistance in determining which methods are available - ease of tracing where a method call goes. - not future proof -- for example, if a method name gets changed or moved, the code using the method still compiles. If we lose all these things, there must be *something* we gain by doing this, right?There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Also, what is the benefit of doing something like this versus specifically calling the dispatcher instead of having the compiler translate it?Probably that's more of a "last mile" thing. Andrei
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsacm8$1gj9$2 digitalmars.com...There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.
Apr 17 2009
Nick Sabalausky:Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python. In Ruby it is more common. Usually in such languages such things are less dangerous because the code contains lot of tests anyway. Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet. Bye, bearophileThere are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.
Apr 17 2009
On 17/04/2009 21:34, bearophile wrote:Nick Sabalausky:just like anything in life this can be overused. This is a very useful tool in a programmer's toolbox for when you need, for example, to quickly experiment with something or do an urgent fix. It's like when you build a house you have it properly designed and have solid foundations but after the house is built you can still redesign internally without rebuilding the entire house.Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python. In Ruby it is more common. Usually in such languages such things are less dangerous because the code contains lot of tests anyway. Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet. Bye, bearophileThere are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.
Apr 17 2009
On Fri, 17 Apr 2009 14:49:37 -0400, Yigal Chripun <yigal100 gmail.com> wrote:On 17/04/2009 21:34, bearophile wrote:It's more like adding another outside door. Try doing that ;) (BTW, removing one is easy, but that kind of doesn't apply here...) changing internals in code is easy, that's why we use OOP. Changing APIs is not. -SteveNick Sabalausky:just like anything in life this can be overused. This is a very useful tool in a programmer's toolbox for when you need, for example, to quickly experiment with something or do an urgent fix. It's like when you build a house you have it properly designed and have solid foundations but after the house is built you can still redesign internally without rebuilding the entire house.Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python. In Ruby it is more common. Usually in such languages such things are less dangerous because the code contains lot of tests anyway. Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet. Bye, bearophileThere are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.
Apr 17 2009
On 17/04/2009 21:58, Steven Schveighoffer wrote:On Fri, 17 Apr 2009 14:49:37 -0400, Yigal Chripun <yigal100 gmail.com> wrote:I completely disagree. here's a use case from my work: we have executables that take 20+ min to compile and link, written with C, C++, and fortran, and we also have code in JavaScript. when I work on the Javascript code it's very easy and quick to debug and test changes while the program is still running while doing the same with the C++ code is very annoying, every change I want to test requires me to wait 20+ minutes for the re-link. a *HUGE* waste of time and also it's easy to forget what you were doing while you wait. no APIs involved in this case. OOP has nothing to do with this since there are both dynamically typed and statically typed OOP languages (Smalltalk vs. D/JAVA) as well as non-OOP languages (ML vs. LISP). btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job. Having only a hammer makes a person think that "when all you got is a hammer everything looks like a nail" kind of way.On 17/04/2009 21:34, bearophile wrote:It's more like adding another outside door. Try doing that ;) (BTW, removing one is easy, but that kind of doesn't apply here...) changing internals in code is easy, that's why we use OOP. Changing APIs is not. -SteveNick Sabalausky:just like anything in life this can be overused. This is a very useful tool in a programmer's toolbox for when you need, for example, to quickly experiment with something or do an urgent fix. It's like when you build a house you have it properly designed and have solid foundations but after the house is built you can still redesign internally without rebuilding the entire house.Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python. In Ruby it is more common. Usually in such languages such things are less dangerous because the code contains lot of tests anyway. Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet. Bye, bearophileThere are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.
Apr 17 2009
"Yigal Chripun" <yigal100 gmail.com> wrote in message news:gsam1p$1ut7$1 digitalmars.com...On 17/04/2009 21:58, Steven Schveighoffer wrote: btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members. Yea, sure I want more tools in my programmer tool box. But I don't want a minor one that's going to mess up one of my major ones just by being in there.
Apr 17 2009
Nick Sabalausky wrote:"Yigal Chripun" <yigal100 gmail.com> wrote in message news:gsam1p$1ut7$1 digitalmars.com...s/on a class's members/on the members of the class that actively chose that/On 17/04/2009 21:58, Steven Schveighoffer wrote: btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Yea, sure I want more tools in my programmer tool box. But I don't want a minor one that's going to mess up one of my major ones just by being in there.I don't think this argument holds. Andrei
Apr 17 2009
On Fri, 17 Apr 2009 15:55:43 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Nick Sabalausky wrote:Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement? The problem with me is that it doesn't *look* different. If there was some way to denote "call dynamic method" instead of "call static method" or some way to denote "has dynamic methods", then I'd have no problem with it. Even if you were forced to derive from a special base type in order to use dynamic methods, I wouldn't mind that. -Steve"Yigal Chripun" <yigal100 gmail.com> wrote in message news:gsam1p$1ut7$1 digitalmars.com...s/on a class's members/on the members of the class that actively chose that/On 17/04/2009 21:58, Steven Schveighoffer wrote: btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 15:55:43 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range.Nick Sabalausky wrote:Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?"Yigal Chripun" <yigal100 gmail.com> wrote in message news:gsam1p$1ut7$1 digitalmars.com...s/on a class's members/on the members of the class that actively chose that/On 17/04/2009 21:58, Steven Schveighoffer wrote: btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.The problem with me is that it doesn't *look* different.I understand how it could be a problem. The thing is, it is also an advantage.If there was some way to denote "call dynamic method" instead of "call static method" or some way to denote "has dynamic methods", then I'd have no problem with it. Even if you were forced to derive from a special base type in order to use dynamic methods, I wouldn't mind that.Would you like ranges that work very different from built-in arrays, and everybody to special-case around that? By the way, D's AAs suck partly because they aren't like anything. I *really* hate the way D does AAs. Andrei
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsapl6$24ei$1 digitalmars.com...Steven Schveighoffer wrote:That's an inadequate comparison. We *can* make arrays and ranges usable in the same way. But opDotExp cannot make dynamic calls usable in the same way as static calls, because one of the rules of static method invokation is that trying to call a non-existant function results in a compile-time error. The best opDotExp can do it make dynamic calls *seem* the same which is deceptive. If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities: 1. Make attempts to invokation a non-existant static function a runtime error (obviously a bad idea). or 2. Provide a *secondary* syntax to invoke a method that works for both static and dynamic. Such as through a reflection api: traits(new Foo()).invokeMethod("bar");Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range. Would you like ranges that work very different from built-in arrays, and everybody to special-case around that?
Apr 17 2009
Nick Sabalausky wrote:"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsapl6$24ei$1 digitalmars.com...Au contraire, it's a very adequate comparison. We changed the language to support ranges/arrays uniformly. Here, I'll paste your argument with the appropriate changes: ==== But globals acting as members cannot make arrays usable in the same way as user-defined types, because one of the rules of arrays is that trying to call a non-existant member function on an array results in a compile-time error. The best your rule can do it make nonmember calls *seem* the same which is deceptive. ====Steven Schveighoffer wrote:That's an inadequate comparison. We *can* make arrays and ranges usable in the same way. But opDotExp cannot make dynamic calls usable in the same way as static calls, because one of the rules of static method invokation is that trying to call a non-existant function results in a compile-time error. The best opDotExp can do it make dynamic calls *seem* the same which is deceptive.Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range. Would you like ranges that work very different from built-in arrays, and everybody to special-case around that?If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities: 1. Make attempts to invokation a non-existant static function a runtime error (obviously a bad idea). or 2. Provide a *secondary* syntax to invoke a method that works for both static and dynamic. Such as through a reflection api: traits(new Foo()).invokeMethod("bar");If I want to write an algorithm that calls "bar" twice, it should be: void twix(T)(T value) { value.bar(); value.bar(); } NOT void twix(T)(T value) { static if (isDynamicType!T) { value.invokeMethod("bar"); value.invokeMethod("bar"); } else { value.bar(); value.bar(); } } Please at least acknowledge that you are in receipt of this argument. We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations. Andrei
Apr 17 2009
On Fri, 17 Apr 2009 18:01:51 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Nick Sabalausky wrote:Calling global functions as if they were array members does not subvert the type system. It is not even close to the same level of danger that this is. I'm all for expanding runtime introspection that remains within the type system, I'm even for adding some possibility to create dynamically dispatched functions, as long as those functions are called differently from normal functions. I think you would agree that one of the main roles of the compiler is to prevent you from making mistakes before it even gets to runtime. Without knowing which calls the compiler checked and which ones it didn't, I can't know where to spend time scrutinizing."Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsapl6$24ei$1 digitalmars.com...Au contraire, it's a very adequate comparison. We changed the language to support ranges/arrays uniformly. Here, I'll paste your argument with the appropriate changes: ==== But globals acting as members cannot make arrays usable in the same way as user-defined types, because one of the rules of arrays is that trying to call a non-existant member function on an array results in a compile-time error. The best your rule can do it make nonmember calls *seem* the same which is deceptive. ====Steven Schveighoffer wrote:That's an inadequate comparison. We *can* make arrays and ranges usable in the same way. But opDotExp cannot make dynamic calls usable in the same way as static calls, because one of the rules of static method invokation is that trying to call a non-existant function results in a compile-time error. The best opDotExp can do it make dynamic calls *seem* the same which is deceptive.Sure, how do you know that the class actively chose it, or did not actively choose it, or will *never* actively choose it simply by looking at the statement?You shouldn't worry about it as much as you shouldn't when you iterate a built-in array vs. a user-defined range. Would you like ranges that work very different from built-in arrays, and everybody to special-case around that?I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities: 1. Make attempts to invokation a non-existant static function a runtime error (obviously a bad idea). or 2. Provide a *secondary* syntax to invoke a method that works for both static and dynamic. Such as through a reflection api: traits(new Foo()).invokeMethod("bar");If I want to write an algorithm that calls "bar" twice, it should be: void twix(T)(T value) { value.bar(); value.bar(); } NOT void twix(T)(T value) { static if (isDynamicType!T) { value.invokeMethod("bar"); value.invokeMethod("bar"); } else { value.bar(); value.bar(); } } Please at least acknowledge that you are in receipt of this argument.We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking. -Steve
Apr 17 2009
On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Andrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution. For example, I don't have any problem with your Pascalize example, because you have not removed any static typing from the code (i.e. no unexpected noops or exceptions are built in). If there were some way to enforce this, then I think it would be a usable idea. For instance, if you only allow CTFE to specify a function that is called when certain strings are passed in, I don't have a problem with that, because you are simply dispatching the data to strongly typed functions at compile time, which provide compile-time errors when you mess up. -SteveWe are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:There is. Just mark opDot as nothrow.Andrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution.We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.For example, I don't have any problem with your Pascalize example, because you have not removed any static typing from the code (i.e. no unexpected noops or exceptions are built in). If there were some way to enforce this, then I think it would be a usable idea. For instance, if you only allow CTFE to specify a function that is called when certain strings are passed in, I don't have a problem with that, because you are simply dispatching the data to strongly typed functions at compile time, which provide compile-time errors when you mess up. -Steve
Apr 17 2009
Don wrote:Steven Schveighoffer wrote:Not an option. I want to dispatch to methods that might throw exceptions.On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:There is. Just mark opDot as nothrow.Andrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution.We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 18 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Or if the type you are dealing with is irrevocably weakly typed anyway, such as most of the use cases we've mentioned (scripting languages, database rows, Variant).Andrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution. For example, I don't have any problem with your Pascalize example, because you have not removed any static typing from the code (i.e. no unexpected noops or exceptions are built in). If there were some way to enforce this, then I think it would be a usable idea. For instance, if you only allow CTFE to specify a function that is called when certain strings are passed in, I don't have a problem with that, because you are simply dispatching the data to strongly typed functions at compile time, which provide compile-time errors when you mess up. -SteveWe are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 18 2009
On Fri, 17 Apr 2009 23:43:22 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I gave this a lot of thought, and I think here is a possible solution: the main reason I'm hesitant on this idea is because of code like this: class X { auto opDotExp(string fname, T...)(T args) { if(fname == "blah") return foo(args); else if(fname == "blither") return bar(args); // else, nothing happens } } Which leaves code open to lots of compiled code that doesn't do the right thing (or throws some runtime exception). What would be nice is if the default behavior is what statically bound functions do, that is, compile error, and only let the cases be handled which the author expects to handle. For that, I think if we make the following rule, we will see much less code that is poorly written, and I think dynamic functions will be feasible: If the compiler can determine during compilation of an opDotExp instance that the resulting function is empty, then it is a compiler error, just like if you tried to call a function that doesn't exist. This behavior can be overridden by putting a return statement in an otherwise empty function. So for example, the above can be statically determined to compile to nothing if fname is not "blah" or "blither", and therefore would be a compiler error. Of course, if you call functions that are not statically evaluable, then you are back to the danger of truly dynamic bindings, but that would make sense for things that cannot be evaluated at compile time. What do you think? -SteveAndrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution. For example, I don't have any problem with your Pascalize example, because you have not removed any static typing from the code (i.e. no unexpected noops or exceptions are built in). If there were some way to enforce this, then I think it would be a usable idea. For instance, if you only allow CTFE to specify a function that is called when certain strings are passed in, I don't have a problem with that, because you are simply dispatching the data to strongly typed functions at compile time, which provide compile-time errors when you mess up.We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 18 2009
Steven Schveighoffer wrote:I gave this a lot of thought, and I think here is a possible solution: the main reason I'm hesitant on this idea is because of code like this: class X { auto opDotExp(string fname, T...)(T args) { if(fname == "blah") return foo(args); else if(fname == "blither") return bar(args); // else, nothing happens } } Which leaves code open to lots of compiled code that doesn't do the right thing (or throws some runtime exception). What would be nice is if the default behavior is what statically bound functions do, that is, compile error, and only let the cases be handled which the author expects to handle.class X { auto opDotExp(string fname, T...)(T args) { static if(fname == "blah") return foo(args); else static if(fname == "blither") return bar(args); else static assert(0, "Dunno how to "~fname); } } Andrei
Apr 18 2009
On Sat, 18 Apr 2009 14:05:30 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:Yeah, I get that it can be done manually. What I'm suggesting is that the compiler makes sure the static assert occurs if thbe result of compiling the template instance results in an empty function. I look at it like adding methods to a class, you don't have to define which methods are not valid, all methods are by default invalid, only the ones you define are allowed. With opDotExp, you are forced to define not only which calls to it are valid, but which ones aren't. I'm saying, don't require defining which ones aren't, just like if you wanted to add methods to a class. I'm sure I'm not explaining this perfectly... For example, the swizzle example that has been brought up many times, you want to handle 256 possible method names, but there are an infinite number of method names. You don't care about defining what to do in all situations, only in the situations you care about. But without compiler help, you have to. -SteveI gave this a lot of thought, and I think here is a possible solution: the main reason I'm hesitant on this idea is because of code like this: class X { auto opDotExp(string fname, T...)(T args) { if(fname == "blah") return foo(args); else if(fname == "blither") return bar(args); // else, nothing happens } } Which leaves code open to lots of compiled code that doesn't do the right thing (or throws some runtime exception). What would be nice is if the default behavior is what statically bound functions do, that is, compile error, and only let the cases be handled which the author expects to handle.class X { auto opDotExp(string fname, T...)(T args) { static if(fname == "blah") return foo(args); else static if(fname == "blither") return bar(args); else static assert(0, "Dunno how to "~fname); } }
Apr 18 2009
Steven Schveighoffer wrote:On Sat, 18 Apr 2009 14:05:30 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:You'll get a "missing return statement", except in the case where it's void. So it's only that one case where it's a problem.Steven Schveighoffer wrote:Yeah, I get that it can be done manually. What I'm suggesting is that the compiler makes sure the static assert occurs if thbe result of compiling the template instance results in an empty function. I look at it like adding methods to a class, you don't have to define which methods are not valid, all methods are by default invalid, only the ones you define are allowed. With opDotExp, you are forced to define not only which calls to it are valid, but which ones aren't. I'm saying, don't require defining which ones aren't, just like if you wanted to add methods to a class. I'm sure I'm not explaining this perfectly... For example, the swizzle example that has been brought up many times, you want to handle 256 possible method names, but there are an infinite number of method names. You don't care about defining what to do in all situations, only in the situations you care about. But without compiler help, you have to. -SteveI gave this a lot of thought, and I think here is a possible solution: the main reason I'm hesitant on this idea is because of code like this: class X { auto opDotExp(string fname, T...)(T args) { if(fname == "blah") return foo(args); else if(fname == "blither") return bar(args); // else, nothing happens } } Which leaves code open to lots of compiled code that doesn't do the right thing (or throws some runtime exception). What would be nice is if the default behavior is what statically bound functions do, that is, compile error, and only let the cases be handled which the author expects to handle.class X { auto opDotExp(string fname, T...)(T args) { static if(fname == "blah") return foo(args); else static if(fname == "blither") return bar(args); else static assert(0, "Dunno how to "~fname); } }
Apr 18 2009
On Sun, 19 Apr 2009 02:00:50 -0400, Don <nospam nospam.com> wrote:Steven Schveighoffer wrote:I thought that the point of the auto return is that the dynamic function could return anything... -SteveYeah, I get that it can be done manually. What I'm suggesting is that the compiler makes sure the static assert occurs if thbe result of compiling the template instance results in an empty function. I look at it like adding methods to a class, you don't have to define which methods are not valid, all methods are by default invalid, only the ones you define are allowed. With opDotExp, you are forced to define not only which calls to it are valid, but which ones aren't. I'm saying, don't require defining which ones aren't, just like if you wanted to add methods to a class. I'm sure I'm not explaining this perfectly... For example, the swizzle example that has been brought up many times, you want to handle 256 possible method names, but there are an infinite number of method names. You don't care about defining what to do in all situations, only in the situations you care about. But without compiler help, you have to. -SteveYou'll get a "missing return statement", except in the case where it's void. So it's only that one case where it's a problem.
Apr 19 2009
On Sat, 18 Apr 2009 21:43:15 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 17 Apr 2009 23:43:22 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Here is an example of a more sophisticated opDotExp use case that relies on its templated version: A Wrapper struct is a simple wrapper around any arbitrary data. It fully encapsulates the underlying object and never gives it away. A simple example is a reference-counter. You want this object to allow any operations on it, but you want to disallow raw object access. "alias this" is very unsafe in this respect. struct Wrapper(T) { private T t; this(ref T obj) { _obj = obj; // capture. I believe there must be a better way to transfer ownership, but I don't know how } auto opDotExp(string fname, T...)(T args) { return t.opDotExp!(fname, T)(args); // how do you forward a call? Do all types have an implicit opDotExp method, i.e. for any given type T, T.bar == T.opDotExp("bar")? } } class Foo { int bar() { return 42; } void baz(int n) { ... } // ... } auto o = Wrapper(new Foo()); int x = o.bar(); o.baz = -1; Foo f = o; // disallowed! It works by referring all the methods to an underlying object. You'll get a compile-time error if it doesn't have such method or property: o.call(); // Error: no such method That's a great functionality, and you can't do it if opDotExp was a runtime method.On Fri, 17 Apr 2009 21:54:52 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I gave this a lot of thought, and I think here is a possible solution: the main reason I'm hesitant on this idea is because of code like this: class X { auto opDotExp(string fname, T...)(T args) { if(fname == "blah") return foo(args); else if(fname == "blither") return bar(args); // else, nothing happens } } Which leaves code open to lots of compiled code that doesn't do the right thing (or throws some runtime exception). What would be nice is if the default behavior is what statically bound functions do, that is, compile error, and only let the cases be handled which the author expects to handle. For that, I think if we make the following rule, we will see much less code that is poorly written, and I think dynamic functions will be feasible: If the compiler can determine during compilation of an opDotExp instance that the resulting function is empty, then it is a compiler error, just like if you tried to call a function that doesn't exist. This behavior can be overridden by putting a return statement in an otherwise empty function. So for example, the above can be statically determined to compile to nothing if fname is not "blah" or "blither", and therefore would be a compiler error. Of course, if you call functions that are not statically evaluable, then you are back to the danger of truly dynamic bindings, but that would make sense for things that cannot be evaluated at compile time. What do you think? -SteveAndrei wrote:Let me add that if there was a way for syntax to easily allow for unintentional calls to be translated to compile-time errors, I think this would be a workable solution. For example, I don't have any problem with your Pascalize example, because you have not removed any static typing from the code (i.e. no unexpected noops or exceptions are built in). If there were some way to enforce this, then I think it would be a usable idea. For instance, if you only allow CTFE to specify a function that is called when certain strings are passed in, I don't have a problem with that, because you are simply dispatching the data to strongly typed functions at compile time, which provide compile-time errors when you mess up.We are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 18 2009
Steven Schveighoffer wrote:... I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.So we have to write ALL templated code that calls member functions or accesses properties/fields like this? Because otherwise objects may as well not be able to do this, since it wouldn't play with any templates ever. You have to be joking.... -Steve
Apr 17 2009
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gsbini$dga$1 digitalmars.com...Steven Schveighoffer wrote:No, only ones that absolutely need to work with dynamic classes. Which is neither all nor the majority. Though dynamic invokation can absolutely be useful at times, it is, and absolutely should remain, a fringe case.... I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.So we have to write ALL templated code that calls member functions or accesses properties/fields like this?Because otherwise objects may as well not be able to do this, since it wouldn't play with any templates ever. You have to be joking.Joking about keeping my static guarantees? When the only other thing at stake is a little bit of syntactic sugar on some occasional dynamic code? Not a chance.
Apr 17 2009
Nick Sabalausky wrote:"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:gsbini$dga$1 digitalmars.com...But you're getting it exactly, almost rigorously, backwards. Algorithms specify an interface (e.g. implicit in the case of std.algorithm). The proposed feature allows the few to conform to the many, so the onus is exactly where it should.Steven Schveighoffer wrote:No, only ones that absolutely need to work with dynamic classes. Which is neither all nor the majority. Though dynamic invokation can absolutely be useful at times, it is, and absolutely should remain, a fringe case.... I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.So we have to write ALL templated code that calls member functions or accesses properties/fields like this?Some people said quite the same thing about virtual methods. They said it's a really stupid idea because now you can't test code - who knows what the callee is going to do? They could throw, do the wrong thing, etc. They said virtual methods break all guarantees and undermine static typing. They also weren't kidding, and they also were "right". Well, I guess they were kinda missing the point :o). AndreiBecause otherwise objects may as well not be able to do this, since it wouldn't play with any templates ever. You have to be joking.Joking about keeping my static guarantees? When the only other thing at stake is a little bit of syntactic sugar on some occasional dynamic code? Not a chance.
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 18:01:51 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:It's also far away from the same level of opportunity.Au contraire, it's a very adequate comparison. We changed the language to support ranges/arrays uniformly. Here, I'll paste your argument with the appropriate changes: ==== But globals acting as members cannot make arrays usable in the same way as user-defined types, because one of the rules of arrays is that trying to call a non-existant member function on an array results in a compile-time error. The best your rule can do it make nonmember calls *seem* the same which is deceptive. ====Calling global functions as if they were array members does not subvert the type system. It is not even close to the same level of danger that this is.I'm all for expanding runtime introspection that remains within the type system, I'm even for adding some possibility to create dynamically dispatched functions, as long as those functions are called differently from normal functions. I think you would agree that one of the main roles of the compiler is to prevent you from making mistakes before it even gets to runtime. Without knowing which calls the compiler checked and which ones it didn't, I can't know where to spend time scrutinizing.Of course I agree. The thing is, if you decide to use a dynamic type, then it will become like a dynamic type.And will uglify and pessimize all code for the benefit of the few.I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.If you want static and dynamic calls to be really usable in the same way (like iterating over a range vs array), then there's only two possibilities: 1. Make attempts to invokation a non-existant static function a runtime error (obviously a bad idea). or 2. Provide a *secondary* syntax to invoke a method that works for both static and dynamic. Such as through a reflection api: traits(new Foo()).invokeMethod("bar");If I want to write an algorithm that calls "bar" twice, it should be: void twix(T)(T value) { value.bar(); value.bar(); } NOT void twix(T)(T value) { static if (isDynamicType!T) { value.invokeMethod("bar"); value.invokeMethod("bar"); } else { value.bar(); value.bar(); } } Please at least acknowledge that you are in receipt of this argument.You will be surprised. AndreiWe are discussing a language extension. That language extension will allow a type to choose flexibility in defining methods dynamically, while being otherwise integrated syntactically with the current values. This has advantages, but also alters the expectations.As long as it identifies what can be dynamic and what cannot. I can't imagine Walter will go for this with his strict view of hijacking.
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsbjci$f6h$1 digitalmars.com...Of course I agree. The thing is, if you decide to use a dynamic type, then it will become like a dynamic type.I didn't have a problem with that reasoning when Variant was added, because that was just one type. But now we're talking about opening D up to an entire class (no pun intended) of dynamic types. We've got an ointment factory and are now talking about adding a production line for flies and deliberately minimizing isolation. I use D because it's static, if we bring this level of dynamic-ism into it, then I won't be able to keep the flies out of my static ointment. "Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsbjci$f6h$1 digitalmars.com...Steven Schveighoffer wrote:Funny, that's very similar to my reasoning *against* allowing opDotExp. It undermines static typing expectations for the benefit of the few. It's very similar, but just on a smaller scale, to making declarations optional for the sake of those who don't like to use them.I think Nick's point number 2 is that you would have to write the above as: void twix(T)(T value) { value.invokeMethod("bar"); value.invokeMethod("bar"); } which would work whether bar was dynamically or statically defined.And will uglify and pessimize all code for the benefit of the few.
Apr 17 2009
On 18/04/2009 04:54, Steven Schveighoffer wrote:I'm all for expanding runtime introspection that remains within the type system, I'm even for adding some possibility to create dynamically dispatched functions, as long as those functions are called differently from normal functions. -SteveHere's an idea: Allow the use of this feature _only_ for appropriately marked types. dynamic class A {... opDotExp ...} //compiles dynamic struct B {... opDotExp ...} //compiles class A {... opDotExp ...} // compile-error: "please mark class as dynamic" struct B {... opDotExp ...} // as above now you have an easy way to know if a type is dynamic without changing the method invocation syntax. A proper IDE can easily mark those Types as different, for example, using a different color.
Apr 18 2009
Yigal Chripun wrote:On 18/04/2009 04:54, Steven Schveighoffer wrote:The dynamic behavior is indicated by the use of opDotExp. The redundancy of the two notations doesn't quite sit well. AndreiI'm all for expanding runtime introspection that remains within the type system, I'm even for adding some possibility to create dynamically dispatched functions, as long as those functions are called differently from normal functions. -SteveHere's an idea: Allow the use of this feature _only_ for appropriately marked types. dynamic class A {... opDotExp ...} //compiles dynamic struct B {... opDotExp ...} //compiles class A {... opDotExp ...} // compile-error: "please mark class as dynamic" struct B {... opDotExp ...} // as above now you have an easy way to know if a type is dynamic without changing the method invocation syntax. A proper IDE can easily mark those Types as different, for example, using a different color.
Apr 18 2009
Op Sat, 18 Apr 2009 09:24:39 +0200 schreef Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:Not necessarily. dynamic class A { void opDotExp... // compiles } class A { void opDotExp... // error } class A { void nothrow opDotExp... // compiles } But yea its still redundant ofcourse. The 'proper' IDE could color classes which have an opDotExp (thats allowed to throw) differently just aswell.now you have an easy way to know if a type is dynamic without changing the method invocation syntax. A proper IDE can easily mark those Types as different, for example, using a different color.The dynamic behavior is indicated by the use of opDotExp. The redundancy of the two notations doesn't quite sit well. Andrei
Apr 18 2009
Hello Andrei,The dynamic behavior is indicated by the use of opDotExp. The redundancy of the two notations doesn't quite sit well. Andreinot exactly 1-to-1 but: abstract class C { void foo(); } // works class D { void foo(); } // fails: link error
Apr 18 2009
On Sat, 18 Apr 2009 19:46:36 +0400, BCS <none anon.com> wrote:Hello Andrei,Bad example: class D { abstact void foo(); } // worksThe dynamic behavior is indicated by the use of opDotExp. The redundancy of the two notations doesn't quite sit well. Andreinot exactly 1-to-1 but: abstract class C { void foo(); } // works class D { void foo(); } // fails: link error
Apr 18 2009
Hello Denis,On Sat, 18 Apr 2009 19:46:36 +0400, BCS <none anon.com> wrote:So I saw, I'm just saying it's not without precedent.not exactly 1-to-1 but:Bad example:
Apr 18 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsamrs$204u$3 digitalmars.com...Right, that's what I meant, but that's still worse than not having opDotExp at all. If someone wants to do dynamic programming, then ok, fine, even though I think they're making a mistake, they're free to go use a dynamic language. But D is supposed to be a static language. That's why I use it. I don't want that staticness to be hijackable just because some people prefer dynamicness. Obviously, if there's a dynamic feature that *doesn't* interfere with the static stuff (the phobos Variant, for example), then that's great. Toss it in and let people use it if they want. Why should I care? But with opDotExp, its mere *existence* undermines my ability to be sure that non-quoted identifiers are ok as long as they've compiled. That type of tradeoff is obviously fine when the potential benefits are significant enough (operator overloading, for instance). But from everything I've seen so far, opDotExp's benefits are trivial at best. I don't want to have to keep track of "ok, is this class using opDotExp or not, because if it is, then I need to be more careful", just for the sake of a feature that provides such a tiny and questionable benefit.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.s/on a class's members/on the members of the class that actively chose that/
Apr 17 2009
Op Fri, 17 Apr 2009 22:31:04 +0200 schreef Nick Sabalausky <a a.a>:But with opDotExp, its mere *existence* undermines my ability to be sure that non-quoted identifiers are ok as long as they've compiled. That type of tradeoff is obviously fine when the potential benefits are significant enough (operator overloading, for instance). But from everything I've seen so far, opDotExp's benefits are trivial at best. I don't want to have to keep track of "ok, is this class using opDotExp or not, because if it is, then I need to be more careful", just for the sake of a feature that provides such a tiny and questionable benefit.class AbstractConceptInvoker { public void activate(){} } auto a = new AbstractConceptInvoker(); a.activate(); What does my code do? Who knows? It could connect to a DB and delete all tables. It could be an O(infinity) operation... You have no idea until you either read (correct) documentation about it, or look at the code. Now let's go from that obvious observation to opDotExp() You know the class uses opDotExp() because it said so in the docs. Examples that could really benifit from this are: - XMLRPC and other kinds of remoting - Quick access to: XML / JSON / Yaml / Config files / DB access - Calling DLLs without bindings - Lots more All these would mention it in their docs, guaranteed. Because they use opDotExp it's implicitly mentioned. I don't think anyone would tell a documentation generator to list all public methods except opDotExp .. that would be just braindead. And you could generate the docs yourself if you have to code.. So what exactly are you afraid of?!
Apr 18 2009
Op Sat, 18 Apr 2009 12:25:55 +0200 schreef Danny Wilson <bluezenix gmail.com>:Op Fri, 17 Apr 2009 22:31:04 +0200 schreef Nick Sabalausky <a a.a>:What I was really trying to say is: sure you have to keep track of which class uses opDotExp but you won't be thinking about it. You'll be thinking "How do I access this json 'object'?" and then remember you can just access it. With quoted identifiers you'll think exactly the same: "How do i access?" use: ["object"]. In both cases you'll get a runtime exception of some sort and have to take a look at the code if you made typos. HaXe (and Actionscript a little) are great examples of statically-dynamically-typed languages :-) I use static typing pretty much all the time. Just in a few cases I use Dynamic (or this opDotExp like thing) and then I'll know where to look for simple errors like typos. Null pointers are a far more common bug for me but that's beside the point.so far, opDotExp's benefits are trivial at best. I don't want to have to keep track of "ok, is this class using opDotExp or not, because if it is, then I need to be more careful", just for the sake of a feature that provides such a tiny and questionable benefit.So what exactly are you afraid of?!
Apr 18 2009
Danny Wilson wrote:Now let's go from that obvious observation to opDotExp() You know the class uses opDotExp() because it said so in the docs. Examples that could really benifit from this are: - XMLRPC and other kinds of remoting - Quick access to: XML / JSON / Yaml / Config files / DB access - Calling DLLs without bindings - Lots more All these would mention it in their docs, guaranteed. Because they use opDotExp it's implicitly mentioned. I don't think anyone would tell a documentation generator to list all public methods except opDotExp .. that would be just braindead. And you could generate the docs yourself if you have to code..Incidentally, one ugly problem with using opDotExp is that the underlying invocation might allow characters that aren't legal in D identifiers. For example, let's say I have a dynamic object wrapping a JavaScript library, and I want to access a JQuery object. JavaScript allows the '$' character to appear in identifiers, and the JQuery people cleverly used that name for one of their core objects (which, I think, acts as an ID registry, or something like that). So, this is a perfectly legal JQuery expression: var a = $("hello"); Using the opDotExp syntax, I'd ideally prefer to call it like this: auto a = js.$("hello"); But the compiler will reject that syntax, since '$' isn't a legal D identifier. Of course, in cases like that, we'll just use some sort of dynamic invocation method: auto a = js.invoke("$", "hello"); Which makes me think this whole discussion is kind of a waste of time, since every single implementation of opDotExp is going to end up delegating to a string-based dispatcher method anyhow. THAT'S the really interesting discussion. In fact, I think I'll start a new topic... --benji
Apr 27 2009
On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator? If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway. -- Adam D. Ruppe http://arsdnet.net
Apr 17 2009
"Adam D. Ruppe" <destructionator gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d puremagic.com...On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function.What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator? If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway.
Apr 17 2009
Nick Sabalausky wrote:"Adam D. Ruppe" <destructionator gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d puremagic.com...Then why overloadable operators? Just write a function call and call it a day. Also, while we're at it, let's prefix all function calls with the word "call" so it's clear that a call is going on. (Some language did that after all.) The fact of the matter is you're in this discussion only to reaffirm a preconceived opinion. Instead of reiterating your arguments, it might be of great use to listen to those made by others. AndreiOn Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function.What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator? If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway.
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsapu0$24ei$2 digitalmars.com...Then why overloadable operators? Just write a function call and call it a day.Overloadable operators and opDotExp both sacrifice code transparency. In that regard, they're the same. But overloadable operators provide non-trivial benefit. From what I've seen, opDotExp doesn't. The only real argument for opDotExp I've seen so far is for things like DB/DDL/haxe.xml.Fast. I've make counter-arguments to that, but I have yet to see those counter-arguments actually refuted. Instead I keep getting a bunch of "use a dynamic lang and you'll see" hand-waving. And, for the record, I have spent a good deal of time using dynamic langs.Also, while we're at it, let's prefix all function calls with the word "call" so it's clear that a call is going on. (Some language did that after all.)Another apples-and-oranges. In C-style languages, getting rid of "call" does not sacrifice code transparency (unlike op overloading and opDotExp) since function calls can be easily identified at a glance by an identifier followed by parens (and calls/declarations can be easily identified by whether or not they're preceded by a type). As a side note, this is one of the reasons I hate D's parens-are-optional-when-there's-no-arguments feature.The fact of the matter is you're in this discussion only to reaffirm a preconceived opinion. Instead of reiterating your arguments, it might be of great use to listen to those made by others.Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.
Apr 17 2009
Nick Sabalausky wrote:Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing. Andrei
Apr 17 2009
Andrei Alexandrescu Wrote:Nick Sabalausky wrote:I'm no fan of it either. I will be pissed if one day I'm using a D library and a function name typo becomes a runtime error. There is no program too short for me to introduce typos and bugs. Even still, this dynamic stuff does not bother me much because it only gets turned on if the class designer wanted it. I assume that it'd be a corner of the language I could avoid. The use seems reasonable besides sone bicycle shed coloring, so I plan to sit quietly in the corner and await an outcome. My only 2 cents is to use something other than dot for dynamic function invocation. Given how much I plan to use it, it's probably better for me to abstain.Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing. Andrei
Apr 17 2009
Jason House wrote:Andrei Alexandrescu Wrote:I agree. Bare with me on this as I am making some assumptions, I don't follow D2 development very closely ... or D as much as I would like these days :-(. What about using something like '->' for dynamic calls instead of '.'? When you see '.' your safe in the knowledge that at a glance you know said method with said signature exists else the compiler will throw a paddy, when you see '->' you know that method call is evaluated at runtime. This has the added benefit that the same class can be used in compile time checking code and runtime. It actually means a case of "it's another operator" instead of something that requires thought as to how it affects the existing use of '.' (which other replies I have seen people suggesting marking the class as dynamic and what not which means more keywords?). '->' becomes an operator whos default behaviour (using a default implementation in Object) just happens to be too search the type for a matching method signature and call it. Consider below (I not looked into variadic functions so its not complete D code ... excuse my ignorance :-)): interface IServerProxy { open(); close(); void opArrow(char[] methodname, v ...) // Maybe put this in interface so we are forced to overload? otherwise IServerProxy looks like it just opens and closes which is a lie and doesn't enforce the overload of dynamic method calls } class ServerProxy : IServerProxy { public: this() { .. create some stuff ... } void opArrow(char[] methodname, v ...) { if (_validDispatches.contains(methodname)) _messagedispatcher.dispatch(methodname, v[0]); // Send a call with a payload else super.opArrow(methodname, v); } void specialmessage(char[] payload) { ... do special processing ... _messagedispatcher.dispatch("specialmessage", payload); // Send a call with a payload } void open() { ... create network connections yada yada .. } void close() { ... close network connections yada yada .. } } void main() { ServerProxy svr = new ServerProxy(); StaticAsMuchAsPoss(svr); DynamicAsMuchAsPoss(svr); AlsoShowBypassNeedToUpcast(svr); } void StaticAsMuchAsPoss(IServerProxy svr) // Plays with the best of both worlds { svr.open(); // Compile time checked valid svr.message("bob"); // Compile time checked invalid!! svr->message("bob"); // run-time checked valid svr->lalala("bob"); // run-time checked invalid!! HOWEVER through the course of the program it may become valid later on ;-) svr.close(); // Compile time checked valid } void DynamicAsMuchAsPoss(IServerProxy svr) { svr->open(); // run-time checked valid svr->kick("someone"); // run-time checked valid svr->close(); // run-time checked valid } void AlsoShowBypassNeedToUpcast(IServerProxy svr) { svr.open(); // Compile time checked valid svr.specialmessage("bob"); // Compile time checked invalid!! svr->specialmessage("bob"); // run-time checked valid svr.close(); // Compile time checked valid } As you can see StaticAsMuchAsPoss mostly makes compile time checked calls, so for the most part your typo's are all checked, apart from when it comes to dispatching messages then we go runtime (in this case its just a case of syntax sugar like the use of most operators, we could just use a stand alone method called dispatch (or add instead of opAdd) and not be dynamic, result is the same however, just it looks a lil nicer and maybe more appropriate?), so your mostly safe. DynamicAsMuchAsPoss is completely managed via the operator, so it's probably slower due to more runtime checks, since even methods that we could use the '.' for compile time checks have to be dynamically invoked, but the result is the same. AlsoShowBypassNeedToUpcast shows through this method you need not upcast to call those pesky derived methods if you don't want too (although generally I would cast as then its just the cast that's the potential danger line as my use of the derived class can be compile-time checked, that's not to say the use of the dynamic call like that is always bad though, I just wouldn't recommend it :-) ). Seems to me that using the above method seems like less hassle, '.' stays as it has always been used and D can have added dynamic abilities ... or even be used similarly to a dynamic language without breaking old code. The only real issue I see is return types. Seems to me the operator (or even opDotExp) needs some sort of built in variant type to handle being able to returning anything (base types, sturcts, classes, union etc...) (which I think would also have opArrow to do the same as Object allowing for things such as bob->callme()->callmesomethingelse() without casting to Object between each call). What do people think?Nick Sabalausky wrote:I'm no fan of it either. I will be pissed if one day I'm using a D library and a function name typo becomes a runtime error. There is no program too short for me to introduce typos and bugs. Even still, this dynamic stuff does not bother me much because it only gets turned on if the class designer wanted it. I assume that it'd be a corner of the language I could avoid. The use seems reasonable besides sone bicycle shed coloring, so I plan to sit quietly in the corner and await an outcome. My only 2 cents is to use something other than dot for dynamic function invocation. Given how much I plan to use it, it's probably better for me to abstain.Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing. Andrei
Apr 18 2009
Adam Burton wrote:Jason House wrote:That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". AndreiAndrei Alexandrescu Wrote:I agree. Bare with me on this as I am making some assumptions, I don't follow D2 development very closely ... or D as much as I would like these days :-(. What about using something like '->' for dynamic calls instead of '.'?Nick Sabalausky wrote:I'm no fan of it either. I will be pissed if one day I'm using a D library and a function name typo becomes a runtime error. There is no program too short for me to introduce typos and bugs. Even still, this dynamic stuff does not bother me much because it only gets turned on if the class designer wanted it. I assume that it'd be a corner of the language I could avoid. The use seems reasonable besides sone bicycle shed coloring, so I plan to sit quietly in the corner and await an outcome. My only 2 cents is to use something other than dot for dynamic function invocation. Given how much I plan to use it, it's probably better for me to abstain.Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing. Andrei
Apr 18 2009
Andrei Alexandrescu wrote:Adam Burton wrote:You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.Jason House wrote:That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". AndreiAndrei Alexandrescu Wrote:I agree. Bare with me on this as I am making some assumptions, I don't follow D2 development very closely ... or D as much as I would like these days :-(. What about using something like '->' for dynamic calls instead of '.'?Nick Sabalausky wrote:I'm no fan of it either. I will be pissed if one day I'm using a D library and a function name typo becomes a runtime error. There is no program too short for me to introduce typos and bugs. Even still, this dynamic stuff does not bother me much because it only gets turned on if the class designer wanted it. I assume that it'd be a corner of the language I could avoid. The use seems reasonable besides sone bicycle shed coloring, so I plan to sit quietly in the corner and await an outcome. My only 2 cents is to use something other than dot for dynamic function invocation. Given how much I plan to use it, it's probably better for me to abstain.Please do not accuse me of such a thing simply because I haven't changed my opinion. You've held your ground as well, so I could just as easily accuse you of being closed-minded and merely reaffirming a your preconceived opinion. I have indeed listened to the arguments and responded to them.Given my track record, I think it should come at no surprise that I'm not a fan of dynamic typing. Andrei
Apr 18 2009
Adam Burton wrote:Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation. AndreiYou could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 18 2009
On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now. The obvious downside is duplication of features, but this might be able to please everyone.Andrei-- Adam D. Ruppe http://arsdnet.net
Apr 18 2009
Hello Adam,On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now.
Apr 18 2009
BCS wrote:Hello Adam,Yea and that would be bad, since then as far as I am concerned you have destroyed the purpose of templates. Seems to me templates and dynamic calls are sorta there to solve the same problem, how do you write code that is independent of type? Dynamic takes it to extreme and makes the evaluation of methods (or public types variables I don't see how that would be different) and leave it all to runtime which is far more flexible but potentially has holes if the type doesn't meet the requirements. Templates take a more conservative route by still letting you write independent of type but then using the information provided at call time it can still perform static code checks to make sure the type meets its needs, making it a little more safe than dynamic. However soon as you throw some dynamic calls into a template the guarantees usually provided go out the window since the template is letting that none existent member slip by. Consider below, why not just use a completely dynamic function as at least then you know what you are letting yourself in for?: void function(T)(T i) { i.bob(); } void function(Object i) { i.bob(); } In the above both functions do exactly the same thing, only difference is with the template sometimes the call is static sometimes and other times it isn't. All you are saving yourself is maybe a performance improvement (which I admit I would probably use the template for just that reason)? However you've lost the compile-time checking of templates and still add the possibility of typos or bad method names leaking in (consider in my previous example if I removed the open method from ServerProxy, with opDotExp it would take over control of the call to 'open' if I happen to forget to remove the call from somewhere). However then I suppose then you are still screwing over the half and half people by not using dynamic calls in templates. T function(T)(T i) { i.bob(); return i; } Variant function(Variant i) { i.bob(); return i; } Using the dynamic method the user is forced to perform a cast where as you don't with the template version. Ok, proposal draft 2 :-P (bare with me this is mostly a mind dump so I apologize for if I may seem to ramble). So what I said previously still stands. StaticAsMuchAsPoss lives with best of both worlds and therefore if I tomorrow decided to remove the method "open" it would fail with a compile-time error where as DynamicAsMuchAsPoss leaves it till run-time. Object/Variant, or whatever opArrow returns, would implement default behaviour (and opArrow would be abstract) of searching the type for implementations of the provided function name (or it could be a public variable name) and if such a thing exists it executes it else throws a runtime error. This allows what you see in DynamicAsMuchAsPoss and AlsoShowBypassNeedToUpcast to be possible, as well as code like something-On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now.bob(10)->nono(11) without worrying about casts (if nono was implemented asan actual function, so we live dynamically). So we get sort of below. class Object { .... usual .... Object opArrow(char[] name, v...) { if (this.publicmethodexists(name)) return invoke(name, this, v); else if (this.publicvariableexists(name)) return invoke(name, this); else throw NoSuchMemberException(name, v); } .... more usual .... } class A { void bob() {} void opArrow(char[] name, v ...) { if (name == "cheese") dosomething(); else super.opArrow(name, v); } } void main() { A a = new A(); a.bob(); // Compile time valid a.cheese(); // compile time invalid a->cheese(); // runtime valid a->bob(); // runtime valid a.nono(); // Compile time invalid a->nono(); // Runtime invalid Object obj = a; obj.bob(); // Compile time invalid obj.cheese(); // compile time invalid obj->cheese(); // runtime valid obj->bob(); // runtime valid obj.nono(); // Compile time invalid obj->nono(); // Runtime invalid } As for templates then how about a dynamic template call that does 1 or 2 passes through the code to prepare it to be dynamic? How about we replace the '!' with a '?' for the dynamic call, that way we can have strict templates (!) and dynamic temapltes (?). See below using the previously discussed template. T myfunc(T i) { i.bob(); return i; } class MyStrictClass { void bob() {} } MyStrictClass c = myfunc!(MyStrictClass)(new MyStrictClass()); // strict call converts to below (default behaviour where i am not verbose with !() ) MyStrictClass myfunc(MyStrictClass i) { i.bob(); return i; } class MyDynamicClass { void opArrow(char[] name, v ...) { if (name == "bob") something; else super.opArrow(name, v); } } MyDynamicClass c = myfunc?(MyDynamicClass)(new MyDynamicClass()); // dynamic call converts to below // It goes through and each . call is converted to a dynamic call MyDynamicClass myfunc(MyDynamicClass i) { i->bob(); return i; } The above becomes completely dynamic. However that could make it all slow due to dynamic calls everywhere which in some cases may be unnecessary, think about below T myfunc(T i) { i.bob(); i.nono(); return i; } class MyStrictClass { void bob() {} void nono() {} } class MyDynamicClass { void bob() {} void opArrow(char[] name, v ...) { if (name == "nono") something; else super.opArrow(name, v); } } // static myfunc!(MyStrictClass) MyStrictClass myfunc(MyStrictClass i) { i.bob(); i.nono(); return i; } // dynamic myfunc?(MyDynamicClass) MyDynamicClass myfunc(MyDynamicClass i) { i->bob(); // This is unnecessary i->nono(); return i; } // dynamic alternative myfunc?(MyDynamicClass) MyDynamicClass myfunc(MyDynamicClass i) { i.bob(); // Was identified as being there so kept as static i->nono(); // Wasn't found in type definition so made dynamic return i; } So now we get the template attempting to use the best of both worlds and only giving in to being dynamic where necessary, it means that in some cases your dynamic templates would not need to be dynamic at all. The next place I see some potential issue is return types of methods call from dynamic inside the template where it may be again unnecessarily using dynamic. T myfunc(T,U)(T t) { U u = t.bob(); u.something(); return t; } class A { Object opArrow(char[] name, v ...) { if (name == "bob") return call("bob", v); else return super.opArrow(name, v); } } class B { void something() {} } A a = myfunc?(A,B)(new A()); // becomes A myfunc(A t) { B u = t->bob(); // Compile time error, not variant/object u.something(); return t; } You could get around above by replacing U with auto T myfunc(T)(T t) { auto u = t.bob(); u.something(); return t; } A a = myfunc?(A)(new A()); // becomes A myfunc(A t) { auto u = t->bob(); // Gets return as object so from here on it starts to unfold that the rest of the template is dynamic u->something(); // Since this is not object/variant it is forced to dynamic return t; } However that doesn't fix below. U myfunc(T,U)(T t) { auto u = t.bob(); u.something(); return u; } B b = myfunc?(A,B)(new A()); // becomes B myfunc(A t) { auto u = t->bob(); u->something(); // Since this is not object/variant it is forced to dynamic return u; // Doesn't work } Therefore we could add a rule that anything returned in a template from a dynamic call that is being passed to a template variable type is cast to that type (I don't like to just throw casts about, but seems to me that its in the same league as dynamic calls). So the below can happen instead. U myfunc(T,U)(T t) { U u = t.bob(); u.something(); return u; } B b = myfunc?(A,B)(new A()); // becomes B myfunc(A t) { B u = cast(B) t->bob(); // Here is the dynamic aspect of the template u.something(); // We are using B not Object so we can go static in our call return u; } You could argue the above starts making templates more complicated, however I think these are already the sort of things you have to bare in mind with templates and dynamic types anyway. Do that solve the problem? p.s. I can see an issue with other operators turning dynamic in templates if you convert 'a = a + a;' to 'a = a.opAdd(a);' and don't implement opAdd in the type passed into dynamic template call, but that depends how you process the template call .. I don't know :-). I would avoid letting such a thing happen (process the + to opAdd after its done a dynamic pass) otherwise you add a rule that operators can be dynamic in templates but not normal code which is confusing.
Apr 19 2009
Adam Burton wrote:BCS wrote:Just thought as well, in a dynamic template call you would probably disable certain kinds of template constraints. Consider below wouldn't work for a dynamic call without disabling the interface constraint. interface A { void bob(); } class B { void opArrow(char[] name, v...) { if (name == "bob") something; else super.opArrow(name, v); } } void function(T : A)(T i) { i.bob(); } function?(B)(new B()); // Won't work, B does not meet criteria On another note: function?(new B()); // Potential short hand using type infurance(sp?)?? although if you replace '?' with '!' then the short hand becomes ambiguous but I suppose since I say strict should be default then short hand for strict isn't necessaryHello Adam,Yea and that would be bad, since then as far as I am concerned you have destroyed the purpose of templates. Seems to me templates and dynamic calls are sorta there to solve the same problem, how do you write code that is independent of type? Dynamic takes it to extreme and makes the evaluation of methods (or public types variables I don't see how that would be different) and leave it all to runtime which is far more flexible but potentially has holes if the type doesn't meet the requirements. Templates take a more conservative route by still letting you write independent of type but then using the information provided at call time it can still perform static code checks to make sure the type meets its needs, making it a little more safe than dynamic. However soon as you throw some dynamic calls into a template the guarantees usually provided go out the window since the template is letting that none existent member slip by. Consider below, why not just use a completely dynamic function as at least then you know what you are letting yourself in for?: void function(T)(T i) { i.bob(); } void function(Object i) { i.bob(); } In the above both functions do exactly the same thing, only difference is with the template sometimes the call is static sometimes and other times it isn't. All you are saving yourself is maybe a performance improvement (which I admit I would probably use the template for just that reason)? However you've lost the compile-time checking of templates and still add the possibility of typos or bad method names leaking in (consider in my previous example if I removed the open method from ServerProxy, with opDotExp it would take over control of the call to 'open' if I happen to forget to remove the call from somewhere). However then I suppose then you are still screwing over the half and half people by not using dynamic calls in templates. T function(T)(T i) { i.bob(); return i; } Variant function(Variant i) { i.bob(); return i; } Using the dynamic method the user is forced to perform a cast where as you don't with the template version. Ok, proposal draft 2 :-P (bare with me this is mostly a mind dump so I apologize for if I may seem to ramble). So what I said previously still stands. StaticAsMuchAsPoss lives with best of both worlds and therefore if I tomorrow decided to remove the method "open" it would fail with a compile-time error where as DynamicAsMuchAsPoss leaves it till run-time. Object/Variant, or whatever opArrow returns, would implement default behaviour (and opArrow would be abstract) of searching the type for implementations of the provided function name (or it could be a public variable name) and if such a thing exists it executes it else throws a runtime error. This allows what you see in DynamicAsMuchAsPoss and AlsoShowBypassNeedToUpcast to be possible, as well as code like something-On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now.bob(10)->nono(11) without worrying about casts (if nono was implemented asan actual function, so we live dynamically). So we get sort of below. class Object { .... usual .... Object opArrow(char[] name, v...) { if (this.publicmethodexists(name)) return invoke(name, this, v); else if (this.publicvariableexists(name)) return invoke(name, this); else throw NoSuchMemberException(name, v); } .... more usual .... } class A { void bob() {} void opArrow(char[] name, v ...) { if (name == "cheese") dosomething(); else super.opArrow(name, v); } } void main() { A a = new A(); a.bob(); // Compile time valid a.cheese(); // compile time invalid a->cheese(); // runtime valid a->bob(); // runtime valid a.nono(); // Compile time invalid a->nono(); // Runtime invalid Object obj = a; obj.bob(); // Compile time invalid obj.cheese(); // compile time invalid obj->cheese(); // runtime valid obj->bob(); // runtime valid obj.nono(); // Compile time invalid obj->nono(); // Runtime invalid } As for templates then how about a dynamic template call that does 1 or 2 passes through the code to prepare it to be dynamic? How about we replace the '!' with a '?' for the dynamic call, that way we can have strict templates (!) and dynamic temapltes (?). See below using the previously discussed template. T myfunc(T i) { i.bob(); return i; } class MyStrictClass { void bob() {} } MyStrictClass c = myfunc!(MyStrictClass)(new MyStrictClass()); // strict call converts to below (default behaviour where i am not verbose with !() ) MyStrictClass myfunc(MyStrictClass i) { i.bob(); return i; } class MyDynamicClass { void opArrow(char[] name, v ...) { if (name == "bob") something; else super.opArrow(name, v); } } MyDynamicClass c = myfunc?(MyDynamicClass)(new MyDynamicClass()); // dynamic call converts to below // It goes through and each . call is converted to a dynamic call MyDynamicClass myfunc(MyDynamicClass i) { i->bob(); return i; } The above becomes completely dynamic. However that could make it all slow due to dynamic calls everywhere which in some cases may be unnecessary, think about below T myfunc(T i) { i.bob(); i.nono(); return i; } class MyStrictClass { void bob() {} void nono() {} } class MyDynamicClass { void bob() {} void opArrow(char[] name, v ...) { if (name == "nono") something; else super.opArrow(name, v); } } // static myfunc!(MyStrictClass) MyStrictClass myfunc(MyStrictClass i) { i.bob(); i.nono(); return i; } // dynamic myfunc?(MyDynamicClass) MyDynamicClass myfunc(MyDynamicClass i) { i->bob(); // This is unnecessary i->nono(); return i; } // dynamic alternative myfunc?(MyDynamicClass) MyDynamicClass myfunc(MyDynamicClass i) { i.bob(); // Was identified as being there so kept as static i->nono(); // Wasn't found in type definition so made dynamic return i; } So now we get the template attempting to use the best of both worlds and only giving in to being dynamic where necessary, it means that in some cases your dynamic templates would not need to be dynamic at all. The next place I see some potential issue is return types of methods call from dynamic inside the template where it may be again unnecessarily using dynamic. T myfunc(T,U)(T t) { U u = t.bob(); u.something(); return t; } class A { Object opArrow(char[] name, v ...) { if (name == "bob") return call("bob", v); else return super.opArrow(name, v); } } class B { void something() {} } A a = myfunc?(A,B)(new A()); // becomes A myfunc(A t) { B u = t->bob(); // Compile time error, not variant/object u.something(); return t; } You could get around above by replacing U with auto T myfunc(T)(T t) { auto u = t.bob(); u.something(); return t; } A a = myfunc?(A)(new A()); // becomes A myfunc(A t) { auto u = t->bob(); // Gets return as object so from here on it starts to unfold that the rest of the template is dynamic u->something(); // Since this is not object/variant it is forced to dynamic return t; } However that doesn't fix below. U myfunc(T,U)(T t) { auto u = t.bob(); u.something(); return u; } B b = myfunc?(A,B)(new A()); // becomes B myfunc(A t) { auto u = t->bob(); u->something(); // Since this is not object/variant it is forced to dynamic return u; // Doesn't work } Therefore we could add a rule that anything returned in a template from a dynamic call that is being passed to a template variable type is cast to that type (I don't like to just throw casts about, but seems to me that its in the same league as dynamic calls). So the below can happen instead. U myfunc(T,U)(T t) { U u = t.bob(); u.something(); return u; } B b = myfunc?(A,B)(new A()); // becomes B myfunc(A t) { B u = cast(B) t->bob(); // Here is the dynamic aspect of the template u.something(); // We are using B not Object so we can go static in our call return u; } You could argue the above starts making templates more complicated, however I think these are already the sort of things you have to bare in mind with templates and dynamic types anyway. Do that solve the problem? p.s. I can see an issue with other operators turning dynamic in templates if you convert 'a = a + a;' to 'a = a.opAdd(a);' and don't implement opAdd in the type passed into dynamic template call, but that depends how you process the template call .. I don't know :-). I would avoid letting such a thing happen (process the + to opAdd after its done a dynamic pass) otherwise you add a rule that operators can be dynamic in templates but not normal code which is confusing.
Apr 19 2009
Hello Adam,BCS wrote:I see your point but disagree. I see it more as a "what to do if the code author doesn't have full API knowledge?" problem. Templates allow the author of the consuming code to go with a "I'll just assume this can be done and let the compiler check it" approach and the dynamic option allows the author of the producer to go with a "Do whatever you want and if I didn't say what to do with it use this code to figure it out" approach. (In the above, you seeme to be working with the assumption of the non static opDotExp form. I, BTW, see no use for it as it adds no new functionality to D where as the static opDotExp(char[],T...)(T t) form adds a new ability) [ the rest of the post dealt with implications of non-static forms of opDotExp ]Hello Adam,Yea and that would be bad, since then as far as I am concerned you have destroyed the purpose of templates. Seems to me templates and dynamic calls are sorta there to solve the same problem, how do you write code that is independent of type? Dynamic takes it to extreme and makes the evaluation of methods (or public types variables I don't see how that would be different) and leave it all to runtime which is far more flexible but potentially has holes if the type doesn't meet the requirements. Templates take a more conservative route by still letting you write independent of type but then using the information provided at call time it can still perform static code checks to make sure the type meets its needs, making it a little more safe than dynamic. However soon as you throw some dynamic calls into a template the guarantees usually provided go out the window since the template is letting that none existent member slip by.On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now.
Apr 19 2009
BCS wrote:Hello Adam,That's essentially what I was trying to say. What I was adding is that when you add the dynamic calls inside the template you lose some of the compile- time checking (and as mentioned in another post how would you use interface constraint with that?) and therefore your template ends up relying on "Do whatever you want and if I didn't say what to do with it use this code to figure it out" for some portions of the code, so you get a weird hybrid that has stepped on templates more than it has dynamic.BCS wrote:I see your point but disagree. I see it more as a "what to do if the code author doesn't have full API knowledge?" problem. Templates allow the author of the consuming code to go with a "I'll just assume this can be done and let the compiler check it" approach and the dynamic option allows the author of the producer to go with a "Do whatever you want and if I didn't say what to do with it use this code to figure it out" approach.Hello Adam,Yea and that would be bad, since then as far as I am concerned you have destroyed the purpose of templates. Seems to me templates and dynamic calls are sorta there to solve the same problem, how do you write code that is independent of type? Dynamic takes it to extreme and makes the evaluation of methods (or public types variables I don't see how that would be different) and leave it all to runtime which is far more flexible but potentially has holes if the type doesn't meet the requirements. Templates take a more conservative route by still letting you write independent of type but then using the information provided at call time it can still perform static code checks to make sure the type meets its needs, making it a little more safe than dynamic. However soon as you throw some dynamic calls into a template the guarantees usually provided go out the window since the template is letting that none existent member slip by.On Sat, Apr 18, 2009 at 06:10:27PM -0700, Andrei Alexandrescu wrote:Going the other way would be better; '.' works as Andrei wants and '->' is an explicit, "don't use the dynamic stuff" invocation. If it went the other way virtually all template code would end up needing to use '->' for everything just in cases someone wants to pass in a type that uses opDotExp.The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.What if the dot remained exactly like it is now and the -> took the place of the dot in the proposal; regular method calls when possible and forwarded to opExtension (opDotExp needs a better name) when that fails? Thus your generic algorithm can use -> and work in all cases, and the dot operator remains the same as it is now.(In the above, you seeme to be working with the assumption of the non static opDotExp form. I, BTW, see no use for it as it adds no new functionality to D where as the static opDotExp(char[],T...)(T t) form adds a new ability)When you say static opDotExp I am assuming you are talking about the example where someone writes a "struct Wrapper(T)" in just a few lines of code to wrap a type and add logging (I been bit busy to read rest of the threads so I only been replying to stuff following the trail leading up to my post for the most part, till now)? If so then yea that does look nice and seems like something I would use. It also doesn't contain the holes my proposal is attempting to solve since the function name is still evaluated at compile time, so removing 'open' from 'ServerProxy' wouldn't magically turn into a runtime error as the static assert will kick in. I also agree that the none static version of opDotExp doesn't bring new functionality to the table that is worth having. Personally in them cases I would prefer to use dispatch(method, params) directly, it feels less obscure, non-static opDotExp just seems like a bit of syntax sugar with more issues than it is worth. My concern was if that functionality was implemented then using '.' for the dynamic runtime calls means is it would cause more problems than it is worth, so my proposal isn't a proposal to add the feature (since I doubt I would use it) it's one that says if you are going to then I think this method of implementing it is less intrusive.[ the rest of the post dealt with implications of non-static forms of [ opDotExpI am sure I have seen some people still arguing for it (but this thread is so big with lots of sub-threads I am a little confused as to whether people are or whether they have settled to just non-static. Also for me the use of the word dynamic from the beginning and the subject of the thread meant runtime so I wouldn't really consider static opDotExp dynamic, just clever compile-time trickery :-P so talk about that has gone off topic from the subject imo) and if that is the case then the proposal still stands as a method of implementing it. If however people are not arguing for it and have settled on static opDotExp then I quite gladdly remove the proposal :-). Adam
Apr 19 2009
Hello Adam,BCS wrote:OK, it seems that we agree on the one point I'm still interested in running with. I must have been reading the rest of that from the wrong viewpoint. I'll leave it at that.(In the above, you seeme to be working with the assumption of the non static opDotExp form. I, BTW, see no use for it as it adds no new functionality to D where as the static opDotExp(char[],T...)(T t) form adds a new ability)When you say static opDotExp I am assuming you are talking about the example where someone writes a "struct Wrapper(T)" in just a few lines of code to wrap a type and add logging (I been bit busy to read rest of the threads so I only been replying to stuff following the trail leading up to my post for the most part, till now)? If so then yea that does look nice and seems like something I would use. It also doesn't contain the holes my proposal is attempting to solve since the function name is still evaluated at compile time, so removing 'open' from 'ServerProxy' wouldn't magically turn into a runtime error as the static assert will kick in.
Apr 19 2009
On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp. I can only see usages of either when you want to bind to dynamic data (e.g. fields in a database row) or when you want to define a vast number of functions where only a few will be used (i.e. Pascalize or swizzle example). I'm not saying there aren't such usages, I just can't think of any myself. -SteveAndrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 18 2009
On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Variant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 19 2009
Denis Koroskin wrote:On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:I agree, seems to me templates attempt to acheive the same as dynamic calls but in a static way, so expecting a template handle functions that are not there for the most part contradicts its very nature. See my reply to BCS as a potential way around this by extending templates.On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". AndreiVariant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.See my reply to BCS as a potential way around this by extending templates.
Apr 19 2009
On Sun, 19 Apr 2009 06:26:57 -0400, Denis Koroskin <2korden gmail.com> wrote:On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Doesn't the current opDot solution do this? Forwarding all calls to a certain member is not a really compelling argument for changing opDot to allow dynamic method names. -SteveOn Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Variant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 19 2009
On Sun, 19 Apr 2009 10:26:11 -0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Sun, 19 Apr 2009 06:26:57 -0400, Denis Koroskin <2korden gmail.com> wrote:Not to mention, how does the compiler know that it should use range-style foreach instead of opApply-style foreach... In fact, I think any object that uses opDotExp to define the foreachable methods might be unusable in foreach. -SteveOn Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Doesn't the current opDot solution do this? Forwarding all calls to a certain member is not a really compelling argument for changing opDot to allow dynamic method names.On Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Variant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 19 2009
On Sun, 19 Apr 2009 18:26:11 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Sun, 19 Apr 2009 06:26:57 -0400, Denis Koroskin <2korden gmail.com> wrote:opDot is reprecated (use alias this instead) and will be eventually removed. But "alias this" is quite unsafe because it exposes the inner data (which is supposed to be hidden in some case, think of reference counting wrapper - you never want to give raw access to an underlying data). Besides, there are is a use-cases that you can't implement in a way other than opDotExp. For example, add some logging or profiling: struct Profile(T) { private T inner; auto opDotExp(string name, T...)(T args) { profiler.enter(name); scope(exit) profiler.leave(); return <forward a call to 'inner' - how one would do this?>(args); } }On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Doesn't the current opDot solution do this? Forwarding all calls to a certain member is not a really compelling argument for changing opDot to allow dynamic method names. -SteveOn Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Variant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 19 2009
On Sun, 19 Apr 2009 10:42:19 -0400, Denis Koroskin <2korden gmail.com> wrote:On Sun, 19 Apr 2009 18:26:11 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Yes, there are many things that opDotExp can do that opDot or alias this (which is essentially opDot without any code). Hooking every function call on a type seems to be one of the two killer use cases of this feature (the other being defining a large range of functions from which only a small number need to exist). But call forwarding seems not to be one of them. There are better ways to simply forward a call (such as in your variant example). I'm pretty convinced that this is a useful feature, I still have qualms about how it's really easy to define a runtime black hole where the compiler happily compiles empty functions that do nothing instead of complaining about calling a function that does not exist. Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists. And BTW, the answer to your question above I think: mixin("return inner."~name~"(args)"); Andrei demonstrated this usage in his Pascalize example. -SteveOn Sun, 19 Apr 2009 06:26:57 -0400, Denis Koroskin <2korden gmail.com> wrote:opDot is reprecated (use alias this instead) and will be eventually removed. But "alias this" is quite unsafe because it exposes the inner data (which is supposed to be hidden in some case, think of reference counting wrapper - you never want to give raw access to an underlying data). Besides, there are is a use-cases that you can't implement in a way other than opDotExp. For example, add some logging or profiling: struct Profile(T) { private T inner; auto opDotExp(string name, T...)(T args) { profiler.enter(name); scope(exit) profiler.leave(); return <forward a call to 'inner' - how one would do this?>(args); } }On Sun, 19 Apr 2009 05:40:32 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Doesn't the current opDot solution do this? Forwarding all calls to a certain member is not a really compelling argument for changing opDot to allow dynamic method names. -SteveOn Sat, 18 Apr 2009 21:10:27 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Variant variantRange = someRange(); foreach (element; variantRange) { // ... } Variant forwards all the front/back/etc methods to an underlying range.Adam Burton wrote:Hm... the thought just occurred to me. At what time are you going to use opDotExp so an entity be used in an algorithm rather than actually defining the functions directly? For example, if you want to make a class/struct a range, why not just define the functions directly? It seems odd to define them using opDotExp.Andrei Alexandrescu wrote:I apologize for the snapping. There's no excuse really, but let me mention that this thread has been particularly meandering. The point of using "." is not syntactic convenience as much as the ability of the Dynamic structure to work out of the box with algorithms that use the standard notation.You could even write 'noodles' but that doesn't really give me a reason as to why it's absolutely useless. Please clarify, I thought it seemed like a reasonable idea, if it isn't I would like to know why.What about using something like '->' for dynamic calls instead of '.'?That's absolutely useless. If I have to write anything different from "." I might as well write "bloodyMaryBloodyMaryBloodyMary". Andrei
Apr 19 2009
Hello Steven,Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists.split the difference and allow either (but not both): R opDotExp(char[] name)(ArgList) R opDotExp(char[] name, T...)(T)
Apr 19 2009
On Mon, 20 Apr 2009 06:09:28 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:Yes, there are many things that opDotExp can do that opDot or alias this (which is essentially opDot without any code). Hooking every function call on a type seems to be one of the two killer use cases of this feature (the other being defining a large range of functions from which only a small number need to exist). But call forwarding seems not to be one of them. There are better ways to simply forward a call (such as in your variant example). I'm pretty convinced that this is a useful feature, I still have qualms about how it's really easy to define a runtime black hole where the compiler happily compiles empty functions that do nothing instead of complaining about calling a function that does not exist. Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists.That way you loose type safety of arguments.And BTW, the answer to your question above I think: mixin("return inner."~name~"(args)"); Andrei demonstrated this usage in his Pascalize example. -SteveOh, right, I saw his post but forgot that solution. Thanks you!
Apr 20 2009
On Mon, 20 Apr 2009 06:54:21 -0400, Denis Koroskin <2korden gmail.com> wrote:On Mon, 20 Apr 2009 06:09:28 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:No class C { int y; void opDotExp(string fname)(int x) { y = x; } } auto c = new C; c.foo(1); // ok c.foo("hi"); // compile error, no such function. -SteveYes, there are many things that opDotExp can do that opDot or alias this (which is essentially opDot without any code). Hooking every function call on a type seems to be one of the two killer use cases of this feature (the other being defining a large range of functions from which only a small number need to exist). But call forwarding seems not to be one of them. There are better ways to simply forward a call (such as in your variant example). I'm pretty convinced that this is a useful feature, I still have qualms about how it's really easy to define a runtime black hole where the compiler happily compiles empty functions that do nothing instead of complaining about calling a function that does not exist. Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists.That way you loose type safety of arguments.
Apr 20 2009
Steven Schveighoffer wrote:On Mon, 20 Apr 2009 06:54:21 -0400, Denis Koroskin <2korden gmail.com> wrote:Good point. My take is, just have the compiler rewrite a.b(c, d, e) into a.opDot!("b")(c, d, e) and call it a day. After that, the usual language rules enter in action. AndreiOn Mon, 20 Apr 2009 06:09:28 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:No class C { int y; void opDotExp(string fname)(int x) { y = x; } } auto c = new C; c.foo(1); // ok c.foo("hi"); // compile error, no such function. -SteveYes, there are many things that opDotExp can do that opDot or alias this (which is essentially opDot without any code). Hooking every function call on a type seems to be one of the two killer use cases of this feature (the other being defining a large range of functions from which only a small number need to exist). But call forwarding seems not to be one of them. There are better ways to simply forward a call (such as in your variant example). I'm pretty convinced that this is a useful feature, I still have qualms about how it's really easy to define a runtime black hole where the compiler happily compiles empty functions that do nothing instead of complaining about calling a function that does not exist. Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists.That way you loose type safety of arguments.
Apr 20 2009
On Mon, 20 Apr 2009 09:47:53 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Steven Schveighoffer wrote:Haven't used D2 for much stuff, but does this work? I remember reading something about partial IFTI, so if you have opDotExp(string fname, T...) (T args){} and you call opDotExp!("b")(c, d, e) Does it implicitly define T? -SteveOn Mon, 20 Apr 2009 06:54:21 -0400, Denis Koroskin <2korden gmail.com> wrote:Good point. My take is, just have the compiler rewrite a.b(c, d, e) into a.opDot!("b")(c, d, e) and call it a day. After that, the usual language rules enter in action.On Mon, 20 Apr 2009 06:09:28 +0400, Steven Schveighoffer <schveiguy yahoo.com> wrote:No class C { int y; void opDotExp(string fname)(int x) { y = x; } } auto c = new C; c.foo(1); // ok c.foo("hi"); // compile error, no such function. -SteveYes, there are many things that opDotExp can do that opDot or alias this (which is essentially opDot without any code). Hooking every function call on a type seems to be one of the two killer use cases of this feature (the other being defining a large range of functions from which only a small number need to exist). But call forwarding seems not to be one of them. There are better ways to simply forward a call (such as in your variant example). I'm pretty convinced that this is a useful feature, I still have qualms about how it's really easy to define a runtime black hole where the compiler happily compiles empty functions that do nothing instead of complaining about calling a function that does not exist. Also, I don't think the requirement for this feature needs to be for the arguments to be templated, it should be sufficient to have a single string template argument. This way, you can overload opDotExp functions via argument lists.That way you loose type safety of arguments.
Apr 20 2009
Steven Schveighoffer wrote:Haven't used D2 for much stuff, but does this work? I remember reading something about partial IFTI, so if you have opDotExp(string fname, T...) (T args){} and you call opDotExp!("b")(c, d, e) Does it implicitly define T? -SteveIt should, but there's a bug related to variadics (right now it only works with non-variadics); I submitted it recently. Andrei
Apr 20 2009
Andrei Alexandrescu wrote:Steven Schveighoffer wrote:Found it. Walter seems to get genuinely interested in opDot so vote up, fixing this bug may become important starting 2.030 :o). http://d.puremagic.com/issues/show_bug.cgi?id=2615 AndreiHaven't used D2 for much stuff, but does this work? I remember reading something about partial IFTI, so if you have opDotExp(string fname, T...) (T args){} and you call opDotExp!("b")(c, d, e) Does it implicitly define T? -SteveIt should, but there's a bug related to variadics (right now it only works with non-variadics); I submitted it recently.
Apr 20 2009
Adam Burton wrote:What about using something like '->' for dynamic calls instead of '.'? When you see '.' your safe in the knowledge that at a glance you know said method with said signature exists else the compiler will throw a paddy, when you see '->' you know that method call is evaluated at runtime. This has the added benefit that the same class can be used in compile time checking code and runtime.One use I can see for this is the other opDotExp use that's been mentioned in this thread, namely: struct s { opDotExp( string s ) { ... } } s obj; auto command = readInput(); obj->command( ); // calls obj.opDotExp( command ) For message-passing, one could argue that <- would be better than ->, though there are ambiguity problems with that. -- Simen
Apr 19 2009
Nick Sabalausky, el 17 de abril a las 16:38 me escribiste:"Adam D. Ruppe" <destructionator gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d puremagic.com...This is like foreach. In C a for loop is a for loop, you are never calling a bizarre member function when looping. When you see code using foreach, you have to go look the variable definition to see if it's a real array to see what the looping is doing. Do we need foreach? No, it's just syntax sugar. But I think it makes life much more easier... There is a lot of black magic already doing on that makes much harder to see what's really going on with a piece of code (operator overloading?). If you don't like that, you should probably stick to C =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05)On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function.What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator? If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway.
Apr 17 2009
Leandro Lucarella wrote:Nick Sabalausky, el 17 de abril a las 16:38 me escribiste:It's more than just convenience; it's integration. Uniform form allows generic algorithms to operate on a variety of types. Somehow this argument keeps on being ignored in the discussion. Andrei"Adam D. Ruppe" <destructionator gmail.com> wrote in message news:mailman.1171.1239998473.22690.digitalmars-d puremagic.com...This is like foreach. In C a for loop is a for loop, you are never calling a bizarre member function when looping. When you see code using foreach, you have to go look the variable definition to see if it's a real array to see what the looping is doing. Do we need foreach? No, it's just syntax sugar. But I think it makes life much more easier... There is a lot of black magic already doing on that makes much harder to see what's really going on with a piece of code (operator overloading?). If you don't like that, you should probably stick to C =)On Fri, Apr 17, 2009 at 03:54:47PM -0400, Nick Sabalausky wrote:The problem is there would be no way to tell at a glance whether a given class uses opDotExp or not. You'd have to go look it up for every class. So, ok, we could solve that by requiring a different syntax for dynamic invokation. But we already have that: just pass a string to a dispatch function.What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members.Wouldn't the compile time checking remain the same on any class except the Variant (or whatever) which implements the new operator? If it is constrained to one type, the destruction seems like it would be acceptable. You can't trust much on a Variant at compile time anyway.
Apr 17 2009
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message news:gsaqe6$25kf$1 digitalmars.com...Leandro Lucarella wrote:There a point I keep bringing up that keeps getting ignored: the code-obscuring "black magic" that we already have provides real non-trivial benefits. I have yet to see an equally compelling case for the ability to call a dynamic method without an explicit dispatcher.This is like foreach. In C a for loop is a for loop, you are never calling a bizarre member function when looping. When you see code using foreach, you have to go look the variable definition to see if it's a real array to see what the looping is doing. Do we need foreach? No, it's just syntax sugar. But I think it makes life much more easier... There is a lot of black magic already doing on that makes much harder to see what's really going on with a piece of code (operator overloading?). If you don't like that, you should probably stick to C =)It's more than just convenience; it's integration. Uniform form allows generic algorithms to operate on a variety of types. Somehow this argument keeps on being ignored in the discussion.That's not ignored at all, in fact I've already addressed it twice before: A reflection API that supports method invokation allows for generic calling of both static and dynamic functions.
Apr 17 2009
Nick Sabalausky, el 17 de abril a las 17:45 me escribiste:What do you call "non-trivial"? Because I can see people seeing foreach a trivial benefit. After all you can allways write the for loop explicitly calling some methods.There a point I keep bringing up that keeps getting ignored: the code-obscuring "black magic" that we already have provides real non-trivial benefits. I have yet to see an equally compelling case for the ability to call a dynamic method without an explicit dispatcher.There is a lot of black magic already doing on that makes much harder to see what's really going on with a piece of code (operator overloading?). If you don't like that, you should probably stick to C =)The code for that would be so ugly I that nobody will agree to use it... I will be just a non-feature. Are you suggesting writting all generic code using something like traits(invoke, obj, "some_function", args) instead of obj.some_function(args) to be able to be use some dynamic method? -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- - is there a perl version of php?... cause i have cgi-bin access with perl and want to use php scripts.It's more than just convenience; it's integration. Uniform form allows generic algorithms to operate on a variety of types. Somehow this argument keeps on being ignored in the discussion.That's not ignored at all, in fact I've already addressed it twice before: A reflection API that supports method invokation allows for generic calling of both static and dynamic functions.
Apr 17 2009
On 17/04/2009 22:54, Nick Sabalausky wrote:"Yigal Chripun"<yigal100 gmail.com> wrote in message news:gsam1p$1ut7$1 digitalmars.com...I was talking generally about dynamic vs. static typing and didn't address the specific implementation of opDotExp. It's just that I wanted to reply to the posts that argued against dynamic typing altogether.On 17/04/2009 21:58, Steven Schveighoffer wrote: btw, I'm not trying to convince you that dynamic typing is necessary always a better solution. What I'm saying is that I agree with Andrei - we need to be open minded and have as many useful tools as possible in our programmer toolbox. The important thing is to choose the right tool for the job.Typically, yes, having "as many useful tools as possible in our programmer toolbox" is great. But with opDotExp, that's not the whole story. What opDotExp is, is a tool of only occasional use that provides only a small benefit, *and* ends up destroying a much more important tool: compile-time checking on a class's members. Yea, sure I want more tools in my programmer tool box. But I don't want a minor one that's going to mess up one of my major ones just by being in there.
Apr 17 2009
"bearophile" <bearophileHUGS lycos.com> wrote in message news:gsai34$1p9k$1 digitalmars.com...Nick Sabalausky:Interesting, I didn't know that.Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python.There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.Usually in such languages such things are less dangerous because the code contains lot of tests anyway.See, that just sounds to me like the dynamic-ness is just creating extra work for less payoff. I'd rather have my compiler automatically guarantee correctness (when possible) than have to manually create even more tests than I'm already creating and *hope* that they catch all the problems.Some people say that a way to remove most of the downsides of monkey patching is to make it scoped, that is the changes (like a method added or replaced) to a class aren't seen globally in the whole program (like from other modules), but only in the scope where such change is done (and its subscopes). I think I have not seen languages where this is doable yet.That would certainly be better. It sounds very much like extension methods, which I'm a big fan of (but I have yet to see polymorphic extension methods, that would be nice to have). Although I think I would still prefer extension methods (polymorphic or otherwise) be defined/declared statically.
Apr 17 2009
Nick Sabalausky:I'd rather have my compiler automatically guarantee correctness (when possible) than have to manually create even more tests than I'm already creating and *hope* that they catch all the problems.This is a very old discussion about the pro/cons of dynamic/static typing :-) (Also note that in such discussions what is often missing is a really powerful and flexible static type system, like Haskell one :-) ) Anyway, regarding what you say here, note that writing tests in python can be very fast, for example if you use doctests :-) http://docs.python.org/library/doctest.html In Haskell you have other good solutions as QuickCheck that invent tests for you: http://www.cs.chalmers.se/~rjmh/QuickCheck/ In my D code I write almost as many tests as I write in Python (about 0.8-1.5 lines of tests for 1 line of D code, while in Python I write about 1-2.5 lines of tests for each line of code). The D compiler is able to catch some bugs the PythoVM isn't able to, but such errors are usually easy to find and fix in Python code, and such tests are quick to write. But then you have to write tests for the logic of method/functions/classes, and they require some time to be written in both languages. The end result is that writing tests in Python is usually not as bad as you think. Bye, bearophile
Apr 17 2009
"bearophile" <bearophileHUGS lycos.com> wrote in message news:gsam1l$1usu$1 digitalmars.com...The end result is that writing tests in Python is usually not as bad as you think.Maybe so, but I don't see any real benefit from it.
Apr 17 2009
Nick Sabalausky:Maybe so, but I don't see any real benefit from it.Are you asking me suggestions to help you see such benefits? :-) Well, find some tasks typically done in such languages, do some of them for few days, trying to follow the typical ways to solve them, and you will probably see the benefits. Bye, bearophile
Apr 17 2009
Nick Sabalausky wrote:"bearophile" <bearophileHUGS lycos.com> wrote in message news:gsai34$1p9k$1 digitalmars.com...Assuming that you are testing the logic of your application, you will trivially check things like accessing "legnth" rather than "length" -- under the assumption that these two methods would do different things. You would spend approximately no additional testing effort on opDotExp. This doesn't hold if you are not writing tests.Nick Sabalausky:Interesting, I didn't know that.Adding methods at runtime is named "monkey patching", and it is considered a bad practice even in Python.There are people who swear by the ability of adding methods at runtime and changing the inheritance hierarchy dynamically. It makes for a very fluid environment.Personally, I've always seen that as extremely sloppy and haphazard.Usually in such languages such things are less dangerous because the code contains lot of tests anyway.See, that just sounds to me like the dynamic-ness is just creating extra work for less payoff. I'd rather have my compiler automatically guarantee correctness (when possible) than have to manually create even more tests than I'm already creating and *hope* that they catch all the problems.
Apr 17 2009
"Christopher Wright" <dhasenan gmail.com> wrote in message news:gsb05g$2ini$3 digitalmars.com...Assuming that you are testing the logic of your application, you will trivially check things like accessing "legnth" rather than "length" -- under the assumption that these two methods would do different things. You would spend approximately no additional testing effort on opDotExp. This doesn't hold if you are not writing tests.I don't think I understand what you're trying to say. With static languages, I have never written, nor would I ever need to write, a test that checks for the behavior when accessing an object's "legnth" instead of "length".
Apr 17 2009
Nick Sabalausky wrote:"Christopher Wright" <dhasenan gmail.com> wrote in message news:gsb05g$2ini$3 digitalmars.com...And let's say your object suddenly gets a "legnth" field because it's from a library and you start using a newer version of the library. Either that field does the same thing -- in which case it's not a bug to use the wrong one -- or it does something different, in which case your code has a logic error caused by a typo. Testing the logic of your code will catch the latter error and not the former. But the former isn't an error, if it has the same result.Assuming that you are testing the logic of your application, you will trivially check things like accessing "legnth" rather than "length" -- under the assumption that these two methods would do different things. You would spend approximately no additional testing effort on opDotExp. This doesn't hold if you are not writing tests.I don't think I understand what you're trying to say. With static languages, I have never written, nor would I ever need to write, a test that checks for the behavior when accessing an object's "legnth" instead of "length".
Apr 18 2009
Hello Christopher,Testing the logic of your code will catch the latter error and not the former. But the former isn't an error, if it has the same result.IIRC dynamic language do gobs of TDD/unittests because they have no choice for just this reason. Any other approach and you have no clue what you'll get. Given a choice between an option that lets in static checking and one that forces the use of runtime testing/checking, I'll go for the static choice every time. (sorry if I'm getting OT)
Apr 18 2009
Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:RPC is an example that comes into mind There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Corr铆 muchas carreras, tratando de alcanzarte a vos. Pero corr铆a s贸lo y siempre sal铆 煤ltimo.The problem is you're dealing with the class which is overloaded its opDot. You know the risk before hand, you are not going to overload for every classes. Here, you seem to little bit overrate this feature. :) If you want things checked, then you probabely need to go back to static. This dynamic stuff is used for dynamic things only, and as long as you have to do it in the dynamic way that means you have no easy way or even impossible to check it at compiletime and you accept the potential risk like the example you posted.Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it.
Apr 17 2009
"Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417191634.GA15139 homero.springfield.home...Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:But is there any that can't be done with a dispatch function? Besides, as I see it, the opDotExp-style syntax for calling a dynamic method is more limited because unless you're using a scripting language, you can't do: auto foo = new Foo(); char[] func = /* Get from user input */; foo.func(); // Call function the user specified But you can do that with either a dispatch method or a reflection API that supports invokation.Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it.RPC is an example that comes into mind There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =)
Apr 17 2009
Nick Sabalausky, el 17 de abril a las 16:48 me escribiste:"Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417191634.GA15139 homero.springfield.home...You can write anything even with brainfuck. There are no discussion about what's possible and what's not, we are just talking about syntax. I hope the "it can be done" argument stop poping out because we all agree that it's possible to do everything right now. The question is *how* you can do it.Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:But is there any that can't be done with a dispatch function?Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it.RPC is an example that comes into mind There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =)Besides, as I see it, the opDotExp-style syntax for calling a dynamic method is more limited because unless you're using a scripting language, you can't do: auto foo = new Foo(); char[] func = /* Get from user input */; foo.func(); // Call function the user specifiedSo?But you can do that with either a dispatch method or a reflection API that supports invokation.I think the reflection API is needed too, but that's another topic. Both would be great. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Cada movimiento que no se hace, es un movimiento que se pierde. Y cada movimiento que se pierde, se transforma en una mochila. Y las mochilas nos alejan, de nuestros amigos y nuestras amigas. Y nuestros amigos se transforman, en enemigos y en enemigas. Cada movimiento que se hace, es una mochila que se deja.
Apr 17 2009
"Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417231958.GB27625 homero.springfield.home...Nick Sabalausky, el 17 de abril a las 16:48 me escribiste:Please, please, please, let's not delve into the "everything can be done" argument. It only holds for a limited domain (theoretical turing machines and turing computable problems, ie theoretical computability), which this discussion is already well outside of. You can't rewrite Firefox in brainfuck in 3 hours. You can't write a worthwhile embedded OS entirely in JavaScript. You can't write a gameboy app to compute the movements of all the particles in the universe until the end of time and have it run to completion in three seconds. You can't. You can't. You can't. Can't can't can't can't can't. Of course there are things that can't be done. Obviously we're all well aware that computability has nothing to do with this discussion, so I really don't see why you've brought it up. As you said, the question is how we compute whatever we're computing and how we write the code to do so. And there absolutely are indeed certain how's under certain conditions that *cannot* be done. And you did say "There is plenty of magic you can do with dynamic methods", right? You don't want me to misuse the "it's possible to do everything" argument to respond "If there's plenty of magic you can do with dynamic methods, and everything is possible, then I can do all the same magic without anything dynamic", do you? So please, please, please, let's never, ever, ever, ever, ever get into the "everything can be done" again unless we really are entirely within the bounds of theoretical computability. So now, let's try this again: What is this usefulness you speak of that traditional dynamic methods and/or opDotSrc dynamic methods have that is more useful than a dispatch method? Or, were you already counting dispatch methods as a form of dynamic method?"Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417191634.GA15139 homero.springfield.home...You can write anything even with brainfuck. There are no discussion about what's possible and what's not, we are just talking about syntax. I hope the "it can be done" argument stop poping out because we all agree that it's possible to do everything right now. The question is *how* you can do it.Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:But is there any that can't be done with a dispatch function?Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it.RPC is an example that comes into mind There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =)I was merely refuting your impliction (or maybe I misunderstood you?) that opDotExp dynamic methods were more useful.Besides, as I see it, the opDotExp-style syntax for calling a dynamic method is more limited because unless you're using a scripting language, you can't do: auto foo = new Foo(); char[] func = /* Get from user input */; foo.func(); // Call function the user specifiedSo?Ok, glad we at least agree on the need for the reflection stuff :)But you can do that with either a dispatch method or a reflection API that supports invokation.I think the reflection API is needed too, but that's another topic. Both would be great.
Apr 17 2009
Nick Sabalausky, el 18 de abril a las 02:19 me escribiste:"Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417231958.GB27625 homero.springfield.home...Nice speech.Nick Sabalausky, el 17 de abril a las 16:48 me escribiste:Please, please, please, let's not delve into the "everything can be done" argument. It only holds for a limited domain (theoretical turing machines and turing computable problems, ie theoretical computability), which this discussion is already well outside of. You can't rewrite Firefox in brainfuck in 3 hours. You can't write a worthwhile embedded OS entirely in JavaScript. You can't write a gameboy app to compute the movements of all the particles in the universe until the end of time and have it run to completion in three seconds. You can't. You can't. You can't. Can't can't can't can't can't. Of course there are things that can't be done. Obviously we're all well aware that computability has nothing to do with this discussion, so I really don't see why you've brought it up. As you said, the question is how we compute whatever we're computing and how we write the code to do so. And there absolutely are indeed certain how's under certain conditions that *cannot* be done. And you did say "There is plenty of magic you can do with dynamic methods", right? You don't want me to misuse the "it's possible to do everything" argument to respond "If there's plenty of magic you can do with dynamic methods, and everything is possible, then I can do all the same magic without anything dynamic", do you? So please, please, please, let's never, ever, ever, ever, ever get into the "everything can be done" again unless we really are entirely within the bounds of theoretical computability."Leandro Lucarella" <llucax gmail.com> wrote in message news:20090417191634.GA15139 homero.springfield.home...You can write anything even with brainfuck. There are no discussion about what's possible and what's not, we are just talking about syntax. I hope the "it can be done" argument stop poping out because we all agree that it's possible to do everything right now. The question is *how* you can do it.Steven Schveighoffer, el 17 de abril a las 11:27 me escribiste:But is there any that can't be done with a dispatch function?Sure, but what is the reason to need dynamic methods? I'm just trying to understand the usefulness of it.RPC is an example that comes into mind There is plenty of magic you can do with dynamic methods. Just try a dynamic language and see =)So now, let's try this again: What is this usefulness you speak of that traditional dynamic methods and/or opDotSrc dynamic methods have that is more useful than a dispatch method?Uniform (and better) syntax. It's just about that. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- JUNTAN FIRMAS Y HUELLAS POR EL CACHORRO CONDENADO A MUERTE... -- Cr贸nica TV
Apr 18 2009
Leandro Lucarella Wrote:I too am having difficulty in understanding the benefit of this particular proposal. If I understand it right, the string essentially is still static and hence known at compile time? In which case I fail to see the advantage of using this opDotSrc method instead of defining a function. Anyways, I have wanted similar functionality for a different purpose. In graphics is common to do swizzle on vector. A float4 vector has xyzw components and some specialized languages like shaders allow you to do shuffle and replicate the components. float4 vec = float4(1.0f,2.0f,3.0f,4.0f); vec = vec.wzyx; //vec is now (4.0f, 3.0f, 2.0f, 1.0f); vec = vec.xxyy; //vec is now (4.0f, 4.0f, 3.0f, 3.0f); There is no good syntax to implement the swizzles in C++. You can make all of them member functions but the number of possibilities is so huge that is ridiculous to do it by hand. With something like this proposal, it should be easy to implement. Also, *if* there was a default opDotExp dispatcher (which automatically dispatches to the regular member functions) wouldn't it be easier to build interceptor classes? Or to implement class specific tracing? All calls to an object go through an interceptor object which can print debug trace information for example. For the default generated opDotExp the compiler can still do static type checking since it knows opDotExp will forward calls to the defined memeber functions.So now, let's try this again: What is this usefulness you speak of that traditional dynamic methods and/or opDotSrc dynamic methods have that is more useful than a dispatch method?Uniform (and better) syntax. It's just about that.
Apr 18 2009
SandeepK:I too am having difficulty in understanding the benefit of this particular proposal.Read the thread, some of the answers give several use cases.If I understand it right, the string essentially is still static and hence known at compile time?<It can be unknown at compile-time.Anyways, I have wanted similar functionality for a different purpose. In graphics is common to do swizzle on vector. A float4 vector has xyzw components and some specialized languages like shaders allow you to do shuffle and replicate the components. float4 vec = float4(1.0f,2.0f,3.0f,4.0f); vec = vec.wzyx;Note that using dynamic access may be a bit slow for that. On the other hand you can do that in D1 creating a small compile-time function that computes the cartesian product to create the strings of the names of those function methods (to be used as attributes), that you can add with a mixin (and a static foreach, if necessary). I have shown such code here time ago, don't ask me to write it again :-) This is a starting point: const string chars = "xyzw"; foreach (x; Range!(4)) foreach (y; Range!(4)) foreach (y; Range!(4)) foreach (w; Range!(4)) chars[x] ~ chars[y] ~ chars[w] ~ chars[w]; Bye, bearophile
Apr 18 2009
bearophile wrote:SandeepK:How on earth could that happen? It's always known at compile time.I too am having difficulty in understanding the benefit of this particular proposal.Read the thread, some of the answers give several use cases.If I understand it right, the string essentially is still static and hence known at compile time?<It can be unknown at compile-time.I don't see _anything_ dynamic in this proposal, actually.Anyways, I have wanted similar functionality for a different purpose. In graphics is common to do swizzle on vector. A float4 vector has xyzw components and some specialized languages like shaders allow you to do shuffle and replicate the components. float4 vec = float4(1.0f,2.0f,3.0f,4.0f); vec = vec.wzyx;Note that using dynamic access may be a bit slow for that.On the other hand you can do that in D1 creating a small compile-time function that computes the cartesian product to create the strings of the names of those function methods (to be used as attributes), that you can add with a mixin (and a static foreach, if necessary). I have shown such code here time ago, don't ask me to write it again :-) This is a starting point:Yes, but the syntax isn't quite as nice as with this proposal.
Apr 18 2009
Don wrote:I don't see _anything_ dynamic in this proposal, actually.Yes. The amount of confusion in this thread is staggering. I think the right question to ask is, "what does opDotExp bring, that wasn't there before?" Is it reflection of any kind? No. Is it the ability to encode operation names as strings, be they static or dynamic? No. Is it the ability to syntactically replace a statically-provided method name with an equally statically-known string? That's pretty much it. Andrei
Apr 18 2009
Andrei Alexandrescu:Yes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
bearophile wrote:Andrei Alexandrescu:In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. AndreiYes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
在 Sun, 19 Apr 2009 02:16:30 +0800,Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> 写道:bearophile wrote:Depends on the compiler semantic. The compiler can feed the opDot with the variable b if it's a string. The compiler can intepret the opDot that way. Consider: string b = "myfunction"; dynamo.b(1); we can translate this to dynamo.opDot("b",1); and we can also rewrite this to dynamo.opDot(b, 1);( if there's a non-template version of opDot just like the current one I have) and even more we can let the compiler decide which rewrite version it prefers, because compiler can simply firstly try to query if there's a variable named b with type of string in the scope of caller. There's someone posted this sort of dynamic language semantic, and I was astonished and thought it were impossible under the opDot scheme. Yet till now, I finally realize that the compiler gets all source input just as the dynamic language interpreter gets input from a console. There won't be much barrier blocking us from mocking every dynamic features. Just we need to be careful to choose some useful part and equip our static land without much potential risk while developer friendly interface. I have not and don't intend to choose the second rewrite version. Whether we should go the second version is left for more discussion. I think many static language developers won't enjoy the second rewrite version at the first glance. I didn't like it either. Yet, after consider a little bit longer, I start to think it might not be as that bad as the first imagination impression in our own mind. It can be funny to have some code like: string doSomething; if (animal = "dog") doSomething="bark"; if (animal = "human") doSomething="talk"; dynamo_animal.doSomething(); Ok, this may look pretty evil in a static language for many among us. I need to claify that I don't intend to go into that direction till further discussion will be made. The first rewrite version and revised by your template suggestion should be able to do the __getattr__ trick, if I get the idea of __getattr__ correctly. I think bearophile's worry can be alleviated. ;)Andrei Alexandrescu:In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them.Yes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophileAndrei-- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/
Apr 18 2009
davidl wrote:鍦 Sun, 19 Apr 2009 02:16:30 +0800锛孉ndrei Alexandrescu <SeeWebsiteForEmail erdani.org> 鍐欓亾:I agree it "can". I don't agree it "can if it's not out of its mind". That lookup method is extremely unhygienic. Andreibearophile wrote:Depends on the compiler semantic. The compiler can feed the opDot with the variable b if it's a string. The compiler can intepret the opDot that way.Andrei Alexandrescu:In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them.Yes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
On 18/04/2009 21:16, Andrei Alexandrescu wrote:bearophile wrote:what prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.Andrei Alexandrescu:In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. AndreiYes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
Yigal Chripun wrote:On 18/04/2009 21:16, Andrei Alexandrescu wrote:Sure it is possible. It has zero relevance to the topic at hand. Andreibearophile wrote:what prevents D from having an eval function?Andrei Alexandrescu:In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. AndreiYes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
Hello Yigal,On 18/04/2009 21:16, Andrei Alexandrescu wrote:Even then it is *still* going to be compile time. Just a compile time running at runtime... Ooohh, my heads's going to start hearing here in a bit.In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. Andreiwhat prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.
Apr 18 2009
On 19/04/2009 01:22, BCS wrote:Hello Yigal,No it won't. you will call a standard library API at *runtime* with a *runtime* string and get back a pointer to a function that you can call. in fact Some Lisp compilers implement eval() exactly like that. you're thinking in C++ terms. try thinking in Lisp...On 18/04/2009 21:16, Andrei Alexandrescu wrote:Even then it is *still* going to be compile time. Just a compile time running at runtime... Ooohh, my heads's going to start hearing here in a bit.In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. Andreiwhat prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.
Apr 18 2009
Hello Yigal,On 19/04/2009 01:22, BCS wrote:That is exactly what I was thinking of and something I have wanted for some time. But for that to work you need to *compile* the string to a function so there is still a compile time inside that function call. That library function you refer to, for the topic at hand, is no different than DMD and the normal compile process. To give a concrete example: suppose the eval function was done by copying the string to a file, tacking in includes as needed, shelling out to DMD to make a DLL/SO and then loading that file back into the same process. In that case there would could be a compile time resolution. In what way would puling the whole thing inside the first process be different?Hello Yigal,No it won't. you will call a standard library API at *runtime* with a *runtime* string and get back a pointer to a function that you can call.On 18/04/2009 21:16, Andrei Alexandrescu wrote:Even then it is *still* going to be compile time. Just a compile time running at runtime... Ooohh, my heads's going to start hearing here in a bit.In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. Andreiwhat prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.in fact Some Lisp compilers implement eval() exactly like that.The only way I can see that making a difference is if you want that eval function to be able to take code that calls function that don't exist yet and I don't even want to think about what it would take to implement that.you're thinking in C++ terms. try thinking in Lisp...(BTW I may have done more Lisp/schema than C++, saying more about by C++ history than anything else.)
Apr 19 2009
On 19/04/2009 23:33, BCS wrote:Hello Yigal,everything you said is true. there is some sort of a compile-time since the code is getting compiled. But in the above scheme there isn't any real difference between run-time and compile-time and this distinction has lost its meaning. compare the following: process A: 1) use runtime dispatch based on run-time user input 2) generate source code for the above case "on the fly" 2) compile the above code and call it process B: 1) generete templated source code at runtime 2) call run-time compiler module on the above code 3) compiler instantiates the template based on the input at *compile-time* (i.e. compile time dispatch) 4) call the templated instance the above are identical even if implemented differently since that compile-time above is actually part of the run-time. the only difference is the style of coding and I'd argue that the second process is unnecessarily more complex without any gains. if nothing else than the source code generated will be shorter since you wouldn't need to stick "static" everywhere.On 19/04/2009 01:22, BCS wrote:That is exactly what I was thinking of and something I have wanted for some time. But for that to work you need to *compile* the string to a function so there is still a compile time inside that function call. That library function you refer to, for the topic at hand, is no different than DMD and the normal compile process. To give a concrete example: suppose the eval function was done by copying the string to a file, tacking in includes as needed, shelling out to DMD to make a DLL/SO and then loading that file back into the same process. In that case there would could be a compile time resolution. In what way would puling the whole thing inside the first process be different?Hello Yigal,No it won't. you will call a standard library API at *runtime* with a *runtime* string and get back a pointer to a function that you can call.On 18/04/2009 21:16, Andrei Alexandrescu wrote:Even then it is *still* going to be compile time. Just a compile time running at runtime... Ooohh, my heads's going to start hearing here in a bit.In the syntax a.b how would either of a and b be identified at runtime? I mean, you write the code somewhere and it gets compiled. It's not like you're reading "a.b" from the console and then call some eval() function against them. Andreiwhat prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.in fact Some Lisp compilers implement eval() exactly like that.The only way I can see that making a difference is if you want that eval function to be able to take code that calls function that don't exist yet and I don't even want to think about what it would take to implement that.you're thinking in C++ terms. try thinking in Lisp...(BTW I may have done more Lisp/schema than C++, saying more about by C++ history than anything else.)
Apr 19 2009
Hello Yigal,everything you said is true. there is some sort of a compile-time since the code is getting compiled. But in the above scheme there isn't any real difference between run-time and compile-time and this distinction has lost its meaning. compare the following: process A: 1) use runtime dispatch based on run-time user input 2) generate source code for the above case "on the fly" 2) compile the above code and call it process B: 1) generete templated source code at runtime 2) call run-time compiler module on the above code 3) compiler instantiates the template based on the input at *compile-time* (i.e. compile time dispatch) 4) call the templated instance the above are identical even if implemented differently since that compile-time above is actually part of the run-time. the only difference is the style of coding and I'd argue that the second process is unnecessarily more complex without any gains. if nothing else than the source code generated will be shorter since you wouldn't need to stick "static" everywhere.I think you understand my point about what is possible but I'm not sure you are spotting what I'm saying regarding what should be done. I'll try and cleanly state what I'm asserting: a number of red hearings seem to be floating about based on cool uses for truly runtime dynamic function lookup (that we just agreed doesn't exist for the given syntax as for that case, the binding happens at sort sort of compile time). I'm calling them red herrings because those uses can be done with other functionalties that already exist. If we throw those out, the only new functionality remanding that any of this thread has provided is allowing the following syntax: a.b(args); to be used when the type of 'a' doesn't define a 'b'. What a lot of debate seems to be about is if that should be translated to: a.opDotExp("b", args); or a.opDotExp!("b", typeof(args))(args); but that's an easy question (go with option 2) if you note that the transformation is always at /some sort/ of compile time. If you want this and the non-static (a.k.a. the non compile time binding (where you thinking of static like static member and not static if/assert?)) form you can implement the non-static version using existing devices and make the above a trivial shell around. Trying to go the other way doesn't work as there is no way to make static decisions (static if or template specialization) in a purely runtime mode using runtime values. [ot] the annoying thing about this whole thread is that I'd bet a small amount of money that I could convince anyone here of my point in about 5 minuets if I had me, them and a chalkboard in the same room. I think almost all the confusion is not because people would disagree with what I'm trying to say but because there are about 5 different and almost unconnected things people are arguing about: a sort of "A is true"/"No, B is true" where A != B and A != !B and !A != B ... Written language has the advantage that you can be very precise and thought out but has zero real time feedback like you get in a face-to-face and an insanely long delay for what feedback it does have.
Apr 19 2009
Hello BCS, That didn't sound like I intended it to so... Clarification: I think most of us could convince most of the rest of us of the our point given face time because I don't think there are near as many opposing views as it seems. (That is with points of operation, not with issues of syntax and or inclusion of features for which there will never be agreement ;)[ot] the annoying thing about this whole thread is that I'd bet a small amount of money that I could convince anyone here of my point in about 5 minuets if I had me, them and a chalkboard in the same room.About 3 minutes me to figure out what they are arguing and about 2 minutes to show how what I'm arguing is orthogonal to it.I think almost all the confusion is not because people would disagree with what I'm trying to say but because there are about 5 different and almost unconnected things people are arguing about: a sort of "A is true"/"No, B is true" where A != B and A != !B and !A != B ... Written language has the advantage that you can be very precise and thought out but has zero real time feedback like you get in a face-to-face and an insanely long delay for what feedback it does have.
Apr 19 2009
On 20/04/2009 01:13, BCS wrote:Hello Yigal,I was meaning static as in "static if". I agree with what you've written here. I think my point in this sub-thread is a bit side-tracked from the main topic. again, what you said is correct, but since in our example we are discussing compile-time as part of run-time, that means there's no difference between static if and regular if (both are executed at run-time). therefore, you can simplify code by re-factoring it to be regular run-time instead of complicated compile-time that is compiled at run-time. you gain nothing by using compile-time techniques here. in other words, if I'm generating code at *run-time*, there's no point in providing a *compile-time* trivial shell as you mention above. I think my main point was to answer Andrei's post - that an eval() function in a compiled language is possible and that nothing about a compiled language implies that we shouldn't be able to have this.everything you said is true. there is some sort of a compile-time since the code is getting compiled. But in the above scheme there isn't any real difference between run-time and compile-time and this distinction has lost its meaning. compare the following: process A: 1) use runtime dispatch based on run-time user input 2) generate source code for the above case "on the fly" 2) compile the above code and call it process B: 1) generete templated source code at runtime 2) call run-time compiler module on the above code 3) compiler instantiates the template based on the input at *compile-time* (i.e. compile time dispatch) 4) call the templated instance the above are identical even if implemented differently since that compile-time above is actually part of the run-time. the only difference is the style of coding and I'd argue that the second process is unnecessarily more complex without any gains. if nothing else than the source code generated will be shorter since you wouldn't need to stick "static" everywhere.I think you understand my point about what is possible but I'm not sure you are spotting what I'm saying regarding what should be done. I'll try and cleanly state what I'm asserting: a number of red hearings seem to be floating about based on cool uses for truly runtime dynamic function lookup (that we just agreed doesn't exist for the given syntax as for that case, the binding happens at sort sort of compile time). I'm calling them red herrings because those uses can be done with other functionalties that already exist. If we throw those out, the only new functionality remanding that any of this thread has provided is allowing the following syntax: a.b(args); to be used when the type of 'a' doesn't define a 'b'. What a lot of debate seems to be about is if that should be translated to: a.opDotExp("b", args); or a.opDotExp!("b", typeof(args))(args); but that's an easy question (go with option 2) if you note that the transformation is always at /some sort/ of compile time. If you want this and the non-static (a.k.a. the non compile time binding (where you thinking of static like static member and not static if/assert?)) form you can implement the non-static version using existing devices and make the above a trivial shell around. Trying to go the other way doesn't work as there is no way to make static decisions (static if or template specialization) in a purely runtime mode using runtime values.
Apr 19 2009
Hello Yigal,I was meaning static as in "static if". I agree with what you've written here. I think my point in this sub-thread is a bit side-tracked from the main topic.there seems to be a lot of that in this threadagain, what you said is correct, but since in our example we are discussing compile-time as part of run-time, that means there's no difference between static if and regular if (both are executed at run-time).But one is interpreted and the other manifests as machine code, one can happen before the types of variable are resolved the other after, one only evaluates once during the runtime-compiletime and the other runs every time the function is actually called. Seems like a big enough difference to me.therefore, you can simplify code by re-factoring it to be regular run-time instead of complicated compile-time that is compiled at run-time. you gain nothing by using compile-time techniques here.Bare in mind that I'm a compile time techniques junky but I think there is a LOT to be gained (if not in what can be done, it's already Turing compleat after all, then in how and how fast things can be done)in other words, if I'm generating code at *run-time*, there's no point in providing a *compile-time* trivial shell as you mention above.I see what your saying, but based on that you can ague that given a pre compile time code generator (lex/yacc?) compile time code generation (Boost::spirit, my dparse or templates in general) is pointless. Using compile time stuff in runtime generated code could be handy where it makes the generation of the code simpler (think swaths of boilerplate)I think my main point was to answer Andrei's post - that an eval() function in a compiled language is possible and that nothing about a compiled language implies that we shouldn't be able to have this.My point is that there is no reason that having eval should make a difference in how opDotExp works because there is something akin to a compile time between text and evaluation anyway.
Apr 20 2009
Yigal Chripun wrote:what prevents D from having an eval function? suppose someone modifies the DMD front-end to compile a string with the source code of a function in-memory, than this is processed by something based on DDL and what you get is an API call that takes source code in a string and returns a function pointer.I suggest you read Burton Radons' "The Joy and Gibbering Terror of Custom-Loading Executable". http://members.shaw.ca/burton-radons/The%20Joy%20and%20Gibbering%20Terror%20of%20Custom-Loading%20Executables.html -- Simen
Apr 18 2009
bearophile wrote:Andrei Alexandrescu:There are two issues here: - The ability to invoke a method where you did not explicitly create a method with that name. - A standardized way of looking up a method to invoke based on a string, where that string may be created at runtime. You can already do this, but there's no standard interface for it. If there were an interface somewhere, like IDispatch { Variant invoke(string, ...); }, that would be nice. Though it doesn't work with structs. In the former case, the method will not exist unless you call it -- for example, swizzling. This is powerful; it means you can use templates to generate the function body. The latter case doesn't give you very much. I'd like to see it in the standard library, but it wouldn't be called before issuing a MethodMissingException or the like because it isn't applicable.Yes. The amount of confusion in this thread is staggering.I think I have misunderstood about the whole thread then. If the string isn't determined at run time, then this thing isn't useful for my purposes, and it's not close to the object-C as I was talking about, and it's not similar to __getattr__ of Python, etc. Bye, bearophile
Apr 18 2009
在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface). -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
Apr 17 2009
在 Fri, 17 Apr 2009 23:20:53 +0800,davidl <davidl nospam.org> 写道:在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:DDBI can also benefit from it. Consider the use case: myRow.Col1 = "abc"; -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
Apr 17 2009
On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl nospam.org> wrote:鍦 Fri, 17 Apr 2009 23:20:53 +0800锛宒avidl <davidl nospam.org> 鍐欓亾:Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper. Plus it's not terribly hard to write: myRow.set("Col1", "abc"); I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it. -Steve鍦 Fri, 17 Apr 2009 22:24:04 +0800锛孲teven Schveighoffer <schveiguy yahoo.com> 鍐欓亾:DDBI can also benefit from it. Consider the use case: myRow.Col1 = "abc";On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
Apr 17 2009
在 Fri, 17 Apr 2009 23:34:37 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl nospam.org> wrote:Actually in a lot cases, you don't have the time to write the static wrapper. Also for a COM object, you don't want to call it in such ways: comobj.callfunc("ComObjFunc", 3,4,5); You probably want to call it only by comobj.ComObjFunc(3,4,5); Yes static wrapper can solve these all. Problem is not in all cases you want to make a static binding for it. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/在 Fri, 17 Apr 2009 23:20:53 +0800,davidl <davidl nospam.org> 写道:Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper. Plus it's not terribly hard to write: myRow.set("Col1", "abc"); I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it. -Steve在 Fri, 17 Apr 2009 22:24:04 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道:DDBI can also benefit from it. Consider the use case: myRow.Col1 = "abc";On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
Apr 17 2009
"davidl" <davidl nospam.org> wrote in message news:op.usjfexkpj5j59l my-tomato...在 Fri, 17 Apr 2009 23:34:37 +0800,Steven Schveighoffer <schveiguy yahoo.com> 写道: Actually in a lot cases, you don't have the time to write the static wrapper. Also for a COM object, you don't want to call it in such ways: comobj.callfunc("ComObjFunc", 3,4,5); You probably want to call it only by comobj.ComObjFunc(3,4,5); Yes static wrapper can solve these all. Problem is not in all cases you want to make a static binding for it.Solution: Create a dispatch function like callfunc above, then use a mixin to generate static callfunc wrappers for any functions that you already know you want. That way, you can have your trivial-to-create static bindings and sidestep them too. ;)
Apr 17 2009
Steven Schveighoffer wrote:On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl nospam.org> wrote:I believe it is entirely syntax sugar. It's no different to: foo(char [] funcname, T...) (T args){} But it allows you to eliminate the foo!("funcname")(args) with funcname(args). Which is a _very_ significant improvement. BTW, I think it _must_ be done as a template, as Andrei suggested. In the original, you have serious problems with delegates, for example, since the function being called has one more parameter (the function name) than it pretends to have.鍦 Fri, 17 Apr 2009 23:20:53 +0800锛宒avidl <davidl nospam.org> 鍐欓亾:Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper. Plus it's not terribly hard to write: myRow.set("Col1", "abc"); I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it. -Steve鍦 Fri, 17 Apr 2009 22:24:04 +0800锛孲teven Schveighoffer <schveiguy yahoo.com> 鍐欓亾:DDBI can also benefit from it. Consider the use case: myRow.Col1 = "abc";On Fri, 17 Apr 2009 09:44:09 -0400, Leandro Lucarella <llucax gmail.com> wrote:Actually this can help ddl project to work more nicely. Consider you can call plugin code directly without static bindings. And I believe delphi COM variant use some similar trick. It allows you call COM object without static bindings. Sometimes it's troublesome to get the static bindings, and you only need one piece of little function(you won't need the whole interface).I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()?I think it translates to opDotExp("qq") = 5 Without knowing the signature of qq, how is the compiler supposed to infer that it is a property? In fact, I think this might be a limitation of this syntax, you can't define dynamic properties. I for one, can't really see a huge benefit, but then again, I don't normally work with dynamic-type langauges. It looks to me like a huge hole that the compiler will ignore bugs that would have been caught if the methods were strongly typed:
Apr 17 2009
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.usjevzhseav7ka steves.networkengines.com...On Fri, 17 Apr 2009 11:27:57 -0400, davidl <davidl nospam.org> wrote:I think some sort of paramaterized property would be far better (I *think* we can do these, right?): myRow.col("Col1") = "abc"; myRow.col["Col1"] = "abc";DDBI can also benefit from it. Consider the use case: myRow.Col1 = "abc";Yes, this case does make sense, but I would still probably rather write a statically-typed wrapper. Plus it's not terribly hard to write: myRow.set("Col1", "abc");I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.Same here. So far, it just doesn't seem worth the loss of knowing at a glance what is and what might not be verified at compile-time. If I wanted to be throwing compile-time guarantees out the window, I'd go use PHP.
Apr 17 2009
Nick Sabalausky, el 17 de abril a las 14:45 me escribiste:Being able to do it doesn't mean you have to use it always. You don't loose anything if you don't use it =) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- The diference is simple: hackers build things, crackers break them.I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.Same here. So far, it just doesn't seem worth the loss of knowing at a glance what is and what might not be verified at compile-time. If I wanted to be throwing compile-time guarantees out the window, I'd go use PHP.
Apr 17 2009
Leandro Lucarella wrote:Nick Sabalausky, el 17 de abril a las 14:45 me escribiste:Correction: You don't lose anything if *nobody you interact with* uses it. A feature that is wide open to abuse is dangerous, even if you'll never abuse it yourself. The feature has to be worth using.Being able to do it doesn't mean you have to use it always. You don't loose anything if you don't use it =)I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.Same here. So far, it just doesn't seem worth the loss of knowing at a glance what is and what might not be verified at compile-time. If I wanted to be throwing compile-time guarantees out the window, I'd go use PHP.
Apr 17 2009
Don wrote:Leandro Lucarella wrote:On the other hand, using the feature requires some due diligence. It doesn't strike me as a dangerous feature that's also the path of last resistance, like casts. AndreiNick Sabalausky, el 17 de abril a las 14:45 me escribiste:Correction: You don't lose anything if *nobody you interact with* uses it. A feature that is wide open to abuse is dangerous, even if you'll never abuse it yourself. The feature has to be worth using.Being able to do it doesn't mean you have to use it always. You don't loose anything if you don't use it =)I'm not yet convinced, but it remains to be seen if there is some killer functionality that cannot be had without it.Same here. So far, it just doesn't seem worth the loss of knowing at a glance what is and what might not be verified at compile-time. If I wanted to be throwing compile-time guarantees out the window, I'd go use PHP.
Apr 17 2009
Leandro Lucarella:Being able to do it doesn't mean you have to use it always. You don't loose anything if you don't use it =)It adds complexity to the language. More things to know and remember and understand, and so on. Generally adding complexity has a cost. Bye, bearophile
Apr 17 2009
bearophile wrote:Leandro Lucarella:I agree. I think in this case the complexity addition is well worth the benefits. AndreiBeing able to do it doesn't mean you have to use it always. You don't loose anything if you don't use it =)It adds complexity to the language. More things to know and remember and understand, and so on. Generally adding complexity has a cost. Bye, bearophile
Apr 17 2009
在 Fri, 17 Apr 2009 21:44:09 +0800,Leandro Lucarella <llucax gmail.com> 写道:davidl, el 17 de abril a las 14:31 me escribiste:Thanks, the example here v.qq returns a B object, and then the assignment kicks in, therefore it calls B.opAssign(5), thus the i member of that B instance is 5. -- 使用 Opera 革命性的电子邮件客户程序: http://www.opera.com/mail/After tweaking dmd a bit litte, i get the dotexp overloading work. The following is the test code: import std.stdio; class c { B opDotExp(char[] methodname,...) { writefln("god it works ", methodname); return new B(); } void opAdd(int j) { } void test() { } } class a:c { } class B { int i; B opAssign(int k){ i=k; return this; } } char[] v1; void func(char[] v, ...){} void main() { a v=new a; v.test(); v.dynamicmethod(3,4); //v.qq = 5; writefln((v.qq = 5).i); } it generates the output: god it works dynamicmethod god it works qq 5 Any comments? Do you like this feature?This is awsome indeed. I'd love to see it in the specs. The suggestion of making opDotExp a template it's good one too. I guess that now that opDot is replaced by alias this, opDot can be used for this instead of opDotExp. I don't fully understand the example though. In writefln((v.qq = 5).i), how is that B.i is assigned to 5 if the opDotExp("qq", 5) don't propagate the 5 to the new B()? Thanks for the great job.
Apr 17 2009
Andrei Alexandrescu:Pascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works againI can show something even more extreme :-) What we are discussing in this thread is named the __getattr__ method in Python: http://docs.python.org/reference/datamodel.html#object.__getattr__ Note that in Python there's something even more powerful, __getattribute__: http://docs.python.org/reference/datamodel.html#object.__getattribute__ So I have created this, that I actually use in a large Graph class of mine that has many methods: http://code.activestate.com/recipes/409000/ Such class can be used from the interactive shell too, to play with graphs in an interactive way, modify them, plot them, etc. Often you may not remember the name of a method you need, or you may mistype it. In such situation __getattr__ is being called. It collects the class method names, removed the useless ones, and performs a similarity search between the given wrong method name and the strings in that list. Then returns the 4-5 most similar ones, each one followed by their docstring, that shows the function signature and the purpose of the method. So you can usually find the method you were looking for, and use it. This is useful both when using such Graph class from the command line and when you are writing code without an IDE that helps you finding method names. That Python code of mine becomes doable in D too (using for example my very fast approximate string distance. This is a case where you don't need the list of changes, but just the distance number. So superdan can rest in peace). Bye, bearophile
Apr 18 2009
bearophile wrote:Andrei Alexandrescu:There's an interesting idea... Instead of "No member 'foo'", you could have "No member 'foo'; did you mean 'far' or 'fur'?" -- DanielPascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works againI can show something even more extreme :-) What we are discussing in this thread is named the __getattr__ method in Python: http://docs.python.org/reference/datamodel.html#object.__getattr__ Note that in Python there's something even more powerful, __getattribute__: http://docs.python.org/reference/datamodel.html#object.__getattribute__ So I have created this, that I actually use in a large Graph class of mine that has many methods: http://code.activestate.com/recipes/409000/ Such class can be used from the interactive shell too, to play with graphs in an interactive way, modify them, plot them, etc. Often you may not remember the name of a method you need, or you may mistype it. In such situation __getattr__ is being called. It collects the class method names, removed the useless ones, and performs a similarity search between the given wrong method name and the strings in that list. Then returns the 4-5 most similar ones, each one followed by their docstring, that shows the function signature and the purpose of the method. So you can usually find the method you were looking for, and use it. This is useful both when using such Graph class from the command line and when you are writing code without an IDE that helps you finding method names. That Python code of mine becomes doable in D too (using for example my very fast approximate string distance. This is a case where you don't need the list of changes, but just the distance number. So superdan can rest in peace). Bye, bearophile
Apr 18 2009
Daniel Keep wrote:bearophile wrote:Heh. The string kernels in std.numeric (http://erdani.dreamhosters.com/d/web/phobos/std_numeric.html) are to help with exactly that. AndreiAndrei Alexandrescu:There's an interesting idea... Instead of "No member 'foo'", you could have "No member 'foo'; did you mean 'far' or 'fur'?" -- DanielPascalize!S s; s.foo(); // works s.Foo(); // works too s.fOo(); // yup, works againI can show something even more extreme :-) What we are discussing in this thread is named the __getattr__ method in Python: http://docs.python.org/reference/datamodel.html#object.__getattr__ Note that in Python there's something even more powerful, __getattribute__: http://docs.python.org/reference/datamodel.html#object.__getattribute__ So I have created this, that I actually use in a large Graph class of mine that has many methods: http://code.activestate.com/recipes/409000/ Such class can be used from the interactive shell too, to play with graphs in an interactive way, modify them, plot them, etc. Often you may not remember the name of a method you need, or you may mistype it. In such situation __getattr__ is being called. It collects the class method names, removed the useless ones, and performs a similarity search between the given wrong method name and the strings in that list. Then returns the 4-5 most similar ones, each one followed by their docstring, that shows the function signature and the purpose of the method. So you can usually find the method you were looking for, and use it. This is useful both when using such Graph class from the command line and when you are writing code without an IDE that helps you finding method names. That Python code of mine becomes doable in D too (using for example my very fast approximate string distance. This is a case where you don't need the list of changes, but just the distance number. So superdan can rest in peace). Bye, bearophile
Apr 18 2009
Andrei Alexandrescu wrote:Daniel Keep wrote:I remember, but can't find, some famous programmer posted to the net a simple spell checking algorithm that worked by counting letter additions, deletions, and transpositions to determine best matches.There's an interesting idea... Instead of "No member 'foo'", you could have "No member 'foo'; did you mean 'far' or 'fur'?"Heh. The string kernels in std.numeric (http://erdani.dreamhosters.com/d/web/phobos/std_numeric.html) are to help with exactly that.
Apr 18 2009
Walter Bright wrote:Andrei Alexandrescu wrote:I don't know who the famous programmer was but it sounds like he was referring to one of the edit distances. std.algorithm has an implementation of the popular Levenshtein distance. http://erdani.dreamhosters.com/d/web/phobos/std_algorithm.html#levenshteinDistance String kernels go way beyond that because they count the weighted length of all gapped substrings common to two strings. http://erdani.dreamhosters.com/d/web/phobos/std_numeric.html#gapWeightedSimilarity With such a similarity, more subtle errors can be detected. AndreiDaniel Keep wrote:I remember, but can't find, some famous programmer posted to the net a simple spell checking algorithm that worked by counting letter additions, deletions, and transpositions to determine best matches.There's an interesting idea... Instead of "No member 'foo'", you could have "No member 'foo'; did you mean 'far' or 'fur'?"Heh. The string kernels in std.numeric (http://erdani.dreamhosters.com/d/web/phobos/std_numeric.html) are to help with exactly that.
Apr 18 2009
A simple command line spell checker would be a cool demonstration of this!
Apr 18 2009
Walter Bright wrote:A simple command line spell checker would be a cool demonstration of this!$ man bash /cdspell If set, minor errors in the spelling of a directory com- ponent in a cd command will be corrected. The errors checked for are transposed characters, a missing charac- ter, and one character too many. If a correction is found, the corrected file name is printed, and the com- mand proceeds. This option is only used by interactive shells.
Apr 18 2009
Daniel Keep, el 18 de abril a las 19:08 me escribiste:Git[1] added that feature for Git commands recently and even when it's not really *that* useful, is a nice feature =) Maybe something like "candidates are: ..." following by each method and file location (to empower IDEs) can be done. I mean, the DMD frontend could do that, not opDot(Exp), of course ;) -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Software is like sex: it's better when it's free. -- Linus TorvaldsSo I have created this, that I actually use in a large Graph class of mine that has many methods: http://code.activestate.com/recipes/409000/ Such class can be used from the interactive shell too, to play with graphs in an interactive way, modify them, plot them, etc. Often you may not remember the name of a method you need, or you may mistype it. In such situation __getattr__ is being called. It collects the class method names, removed the useless ones, and performs a similarity search between the given wrong method name and the strings in that list. Then returns the 4-5 most similar ones, each one followed by their docstring, that shows the function signature and the purpose of the method. So you can usually find the method you were looking for, and use it. This is useful both when using such Graph class from the command line and when you are writing code without an IDE that helps you finding method names. That Python code of mine becomes doable in D too (using for example my very fast approximate string distance. This is a case where you don't need the list of changes, but just the distance number. So superdan can rest in peace). Bye, bearophileThere's an interesting idea... Instead of "No member 'foo'", you could have "No member 'foo'; did you mean 'far' or 'fur'?"
Apr 18 2009
davidl wrote:Any comments? Do you like this feature?And here it is (called opDispatch, Michel Fortin's suggestion): http://www.dsource.org/projects/dmd/changeset?new=trunk%2Fsrc 268&old=trunk%2Fsrc 267
Nov 28 2009
Walter Bright:And here it is (called opDispatch, Michel Fortin's suggestion):<That's short code. Do you like my related suggestion of opDynamic (that works with run-time method names)? Bye, bearophile
Nov 28 2009
bearophile wrote:Walter Bright:opDispatch can be written to do runtime method names, no language changes needed.And here it is (called opDispatch, Michel Fortin's suggestion):<That's short code. Do you like my related suggestion of opDynamic (that works with run-time method names)?
Nov 28 2009
Walter Bright:opDispatch can be written to do runtime method names, no language changes needed.Very good. Then the opDynamic name wasn't wrong. Can someone show me a small example of how to use it with runtime method names? Bye, bearophile
Nov 28 2009
bearophile wrote:Can someone show me a small example of how to use it with runtime method names?class C { void dynamic(string s, int i) { ... } void opDispatch(string s)(int i) { dynamic(s, i); } }
Nov 28 2009
On Sun, 29 Nov 2009 00:37:34 +0100, Walter Bright <newshound1 digitalmars.com> wrote:davidl wrote:Just tested it - it does not seem to allow template parameters beyond just the function name. Is this something we can expect in the future? The use case I have is this: struct foo { void opDispatch( string name, T )( T value ) { static if ( is( T == float ) ) { // Do something } else static if ( T == int ){ } else { static assert( false, "Unsupported argument type." ); } } } Thank you, SimenAny comments? Do you like this feature?And here it is (called opDispatch, Michel Fortin's suggestion): http://www.dsource.org/projects/dmd/changeset?new=trunk%2Fsrc 268&old=trunk%2Fsrc 267
Nov 28 2009
Simen kjaeraas wrote:Just tested it - it does not seem to allow template parameters beyond just the function name. Is this something we can expect in the future? The use case I have is this: struct foo { void opDispatch( string name, T )( T value ) { static if ( is( T == float ) ) { // Do something } else static if ( T == int ){ } else { static assert( false, "Unsupported argument type." ); } } }I see. That's a bug, and I'll fix it.
Nov 28 2009