* Top 10 Worst C# Features @ 2015-09-02 10:59 Stefan.Lucks 2015-09-02 17:37 ` Álex R. Mosteo ` (3 more replies) 0 siblings, 4 replies; 31+ messages in thread From: Stefan.Lucks @ 2015-09-02 10:59 UTC (permalink / raw) [-- Attachment #1: Type: text/plain, Size: 2274 bytes --] Eric Lippert from the C# design team has an interesting article on the ten worst features of C#. At least eight of these have been solved in Ada. Did Jean I. time-travel into the future and learned from the C# mistakes, when designing Ada? Lean back and enjoy! http://www.informit.com/articles/article.aspx?p=2425867 BTW, the two issues that are, to some degree, applicable to Ada are #9 Comparison operators for your own arithmetic (e.g., for your own rational numbers). In Ada, the "/="-operator is automatically the negation of "=". Which is great. But given "=", "<", and ">", why does one have to implement "<=" and ">=", as well. (Five Operators, where three would suffice.) (*) The situation with C# is even worse. You need to define/override at least nine methods. #2 Finaliz(ers) are fragile In Ada, the finalize procedure for an object can be called more than once, Finalize should rather not raise an exception, ... apparently, C# finalzisers suffer from similar problems: "any time a finalizer runs, you could argue that the program either has a bug or is in a dangerous state, such as being shut down unexpectedly via a thread abort". The remaining eight C# issues have been solved in Ada. ------- (*) One might argue that two operators, e.g., "=" and "<" would suffice, rather than three. If neither A=B nor A<B, then A>B is obvious, isn't it? But not all sorts of "arithmetic", where you want to take comparisons, have the property that either of A=B, A>B, A<B is true: -- Arithmetic with "special values", such as "Not a Number" for floating point operations. If A is NaN, then neither A=B nor A>B nor A<B would hold, even if B is also NaN. -- Another example would be sets: A<B would indicate "A is a proper subset of B. If, e.g., A={1} and B={2,3}, then neither A=B nor A<B nor A>B. On the other hand, A <= B should never mean anything different from (A < B) or (A = B)! Similarly for A >= B. -------- I love the taste of Cryptanalysis in the morning! -------- www.uni-weimar.de/de/medien/professuren/mediensicherheit/people/stefan-lucks ----Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany---- ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-02 10:59 Top 10 Worst C# Features Stefan.Lucks @ 2015-09-02 17:37 ` Álex R. Mosteo 2015-09-02 19:39 ` Randy Brukardt ` (2 subsequent siblings) 3 siblings, 0 replies; 31+ messages in thread From: Álex R. Mosteo @ 2015-09-02 17:37 UTC (permalink / raw) Stefan.Lucks@uni-weimar.de wrote: > Eric Lippert from the C# design team has an interesting article on the ten > worst features of C#. At least eight of these have been solved in Ada. Did > Jean I. time-travel into the future and learned from the C# mistakes, when > designing Ada? > > Lean back and enjoy! > > http://www.informit.com/articles/article.aspx?p=2425867 I chuckled at the point: "As Benjamin Franklin (never) said, language designers who give up a little type safety for a little performance will discover they have neither." ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-02 10:59 Top 10 Worst C# Features Stefan.Lucks 2015-09-02 17:37 ` Álex R. Mosteo @ 2015-09-02 19:39 ` Randy Brukardt 2015-09-03 8:14 ` Georg Bauhaus 2015-09-03 8:51 ` gautier_niouzes 2015-10-01 14:03 ` Paul Colin de Gloucester 3 siblings, 1 reply; 31+ messages in thread From: Randy Brukardt @ 2015-09-02 19:39 UTC (permalink / raw) <Stefan.Lucks@uni-weimar.de> wrote in message news:alpine.DEB.2.20.1509021228510.5314@debian... ... >#2 Finaliz(ers) are fragile > >In Ada, the finalize procedure for an object can be called more than once, >Finalize should rather not raise an exception, ... apparently, C# >finalzisers suffer from similar problems: "any time a finalizer runs, you >could argue that the program either has a bug or is in a dangerous state, >such as being shut down unexpectedly via a thread abort". Based on the article, the situation in Ada is far less bad than the C# one. His description of C++ finalizers apply to Ada's as well: "[they] run deterministically, run on the current thread, and never run on partially constructed objects." Moreover, they always run when objects are destroyed, while apparently in C# they don't run for explicit calls to Dispose. Ada's issues come from two things: extremely rare cases involving exceptions where a finalizer might start twice, and the fact that someone can explicitly call it on an object. If one has control over the entire system, neither of these cases need happen; a program like AdaControl can enforce appropriate style rules to avoid problems. If not, it's relatively easy to make Finalize callable multiple times (you just need a "Valid" bit in the object, which is turned off by Finalize; if it's off, Finalize does nothing). Of course, Ada gets this by not supporting garbage collection on objects that have non-trival finalization (such an object cannot be garbage collected until the finalization has run, meaning they have to exist until they go out of scope, meaning no useful garbage collection can happen. Fixing that would probably introduce more problems (although if the points at which garbage collection could happen were appropriately limited it would not be a huge issue; if this issue is ever addressed in Ada, that would have to be the case). In any case, Ada's situation is nothing like the asynchronous mess he describes for C#. It may not be perfect, but it's a heck of a lot better than C#. Randy. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-02 19:39 ` Randy Brukardt @ 2015-09-03 8:14 ` Georg Bauhaus 2015-09-03 9:26 ` Dmitry A. Kazakov 0 siblings, 1 reply; 31+ messages in thread From: Georg Bauhaus @ 2015-09-03 8:14 UTC (permalink / raw) On 02.09.15 21:39, Randy Brukardt wrote: > "[they] run > deterministically, run on the current thread, and never run on partially > constructed objects." > Moreover, they always run when objects are destroyed, while apparently in C# > they don't run for explicit calls to Dispose. Still, finalizers are an accidental bit of design. It uses just scopes and it involves garbage. And while that's something, this very bit is being carried to the limit, perhaps too far: if finalizers are popular, problems pop up with corresponding frequency. What finalization can presumably solve I'd love to see addressed systematically, using language that attaches life cycle events to types. Events addressable in the type's very definition, not attached by implication, testament style, about things to happen while objects are dying. Events becoming part of the type definition, the program then makes the objects react to events while they are still alive and well. Actions will no longer be some "last words" that require additional efforts to get right. Is it possible to produce a scheme that makes attaching "event subprograms", say, well defined? Maybe permissions would be based on visibility of entities referred to? For a start, using subprograms, type T is ... for T'Some_Event use ... or type T is ... with T'Some_Event => ... When new attachments would be desired in deeper scope, maybe one could use some type derived there. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 8:14 ` Georg Bauhaus @ 2015-09-03 9:26 ` Dmitry A. Kazakov 2015-09-03 11:39 ` G.B. 0 siblings, 1 reply; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-03 9:26 UTC (permalink / raw) On Thu, 3 Sep 2015 10:14:35 +0200, Georg Bauhaus wrote: > What finalization can presumably solve I'd love to see addressed > systematically, using language that attaches life cycle events to > types. What a horrific idea... > Is it possible to produce a scheme that makes attaching "event > subprograms", say, well defined? Maybe permissions would be based > on visibility of entities referred to? No. 1. Regarding types there is no any events. It must be clearly understood. Either a type exists or it does not. Furthermore a type is immutable throughout all its life, which is extremely important for substitutability. An object of a type is *same* in all contexts, because the type is same. What you propose is not typed. 2. Regarding finalization, another crucial point. Finalization is *not* an operation. The object ceases to exist after its finalization. Therefore exist certain composition rules of how finalization is defined upon type operations such as aggregation, inheritance etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 9:26 ` Dmitry A. Kazakov @ 2015-09-03 11:39 ` G.B. 2015-09-03 12:00 ` G.B. 2015-09-03 13:47 ` Dmitry A. Kazakov 0 siblings, 2 replies; 31+ messages in thread From: G.B. @ 2015-09-03 11:39 UTC (permalink / raw) On 03.09.15 11:26, Dmitry A. Kazakov wrote: > On Thu, 3 Sep 2015 10:14:35 +0200, Georg Bauhaus wrote: > >> What finalization can presumably solve I'd love to see addressed >> systematically, using language that attaches life cycle events to >> types. > > What a horrific idea... > >> Is it possible to produce a scheme that makes attaching "event >> subprograms", say, well defined? Maybe permissions would be based >> on visibility of entities referred to? > > No. > > 1. Regarding types there is no any events. Yes. Perhaps I should first say what "event" is to name. (The word being used in different contexts, AFAICT.) Extensionally, an event is something that happens at some point in the lifetime of an object, such as being passed, or one of its operations being called (maybe for the 'Nth time). > Either a type exists or it does not. Yes. > Furthermore a type is immutable > throughout all its life, Yes. > An object of a type is *same* in all contexts, because the type is same. While an object doesn't change either identity or type, it does changes state. This is an event, too. > What you propose is not typed. I think that what you might have misunderstood is not typed. :-) > 2. Regarding finalization, another crucial point. Finalization is *not* an > operation. I'm not asking for finalization as an operation. I'm asking for clearly defined hooks made for operations (or something else) for what programmers will now put into Finalize, since there is nothing else where to put it. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 11:39 ` G.B. @ 2015-09-03 12:00 ` G.B. 2015-09-03 13:59 ` Dmitry A. Kazakov 2015-09-03 19:12 ` Randy Brukardt 2015-09-03 13:47 ` Dmitry A. Kazakov 1 sibling, 2 replies; 31+ messages in thread From: G.B. @ 2015-09-03 12:00 UTC (permalink / raw) On 03.09.15 13:39, G.B. wrote: >> An object of a type is *same* in all contexts, because the type is same. > > While an object doesn't change either identity or type, > it does changes state. This is an event, too. Seen from a different angle: What could a type system have to offer to GUI programming? Some kinds of "event" are as ubiquitous in GUI programming as they are essential. Can this be made static? AFAICT, today we have string literals identifying things that can be called (Gtk), or we have selectors (Objective-C) for a similar thing, etc. A mouse click or gesture is thus another kind of event to which programmers might want to attach something that reacts. How would static type systems help, knowing that trying to make them help has allegedly failed in the past? ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 12:00 ` G.B. @ 2015-09-03 13:59 ` Dmitry A. Kazakov 2015-09-03 19:12 ` Randy Brukardt 1 sibling, 0 replies; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-03 13:59 UTC (permalink / raw) On Thu, 3 Sep 2015 14:00:52 +0200, G.B. wrote: > On 03.09.15 13:39, G.B. wrote: >>> An object of a type is *same* in all contexts, because the type is same. >> >> While an object doesn't change either identity or type, >> it does changes state. This is an event, too. > > Seen from a different angle: > What could a type system have to offer to GUI programming? > Some kinds of "event" are as ubiquitous in GUI programming > as they are essential. Can this be made static? Yes it can. See below. > AFAICT, today we have string literals identifying things > that can be called (Gtk), or we have selectors (Objective-C) > for a similar thing, etc. GtkAda has typed events on top of untyped Gtk events. The problem with it is that it is reversed. The interface is of the button, e.g. it is the primitive operations of the button (e.g. On_Button_Clicked), which is useless in most cases. It should have been of the widget handling button events: Button ---------event----------> Handler widget | On_Button_Clicked The operation, and types hierarchy, must be on the right. The controlling parameter is not Button but the handler widget. > A mouse click or gesture is thus > another kind of event to which programmers might want to attach > something that reacts. How would static type systems help, > knowing that trying to make them help has allegedly failed > in the past? The design is that you have a handler interface, e.g. of a button events handler with the primitive operations of event notifications. The widget catching button events implements this interface. Note that differently to Ada or C++ interfaces this one is additive. I.e. if you handle more than one button, the inherited interfaces of do not coalesce. Other examples of this type of inheritance is doubly-linked list header, queue element etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 12:00 ` G.B. 2015-09-03 13:59 ` Dmitry A. Kazakov @ 2015-09-03 19:12 ` Randy Brukardt 2015-09-04 7:33 ` Georg Bauhaus 1 sibling, 1 reply; 31+ messages in thread From: Randy Brukardt @ 2015-09-03 19:12 UTC (permalink / raw) "G.B." <bauhaus@futureapps.invalid> wrote in message news:ms9cm8$leh$1@dont-email.me... ... > AFAICT, today we have string literals identifying things > that can be called (Gtk), or we have selectors (Objective-C) > for a similar thing, etc. A mouse click or gesture is thus > another kind of event to which programmers might want to attach > something that reacts. How would static type systems help, > knowing that trying to make them help has allegedly failed > in the past? I have no idea why you think this is a problem. Claw uses statically defined action routines that one overrides. This is type-safe, it's impossible to handle an action that cannot happen (such as a click on a drawing canvas), and one can easily see that all required actions are handled (they're abstract in that case). GWindows uses (optionally) call-back access-to-subprograns, which definitely have the first two properties (but not the third). The implementation of this (the actual GUI binding) is groddy, but that's because we're trying to build something clean on top of a C implementation that resists that at every step. :-) So I fail to see any problem that isn't being addressed here. Finalization is a very special kettle of fish, because the objects don't exist afterwards. It's needed to provide last wishes to objects, for clean-up of various sorts. (For instance, Claw uses finalization to unhook windows from the active window list, else we'd be calling actions on non-existent windows. There is no other bullet-proof way to do that, if one wants there library to work in the face of exceptions and abort, as well as programmer mistakes [failing to call Close appropriately].) Randy. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 19:12 ` Randy Brukardt @ 2015-09-04 7:33 ` Georg Bauhaus 2015-09-04 21:34 ` Randy Brukardt 0 siblings, 1 reply; 31+ messages in thread From: Georg Bauhaus @ 2015-09-04 7:33 UTC (permalink / raw) On 03.09.15 21:12, Randy Brukardt wrote: > "G.B." <bauhaus@futureapps.invalid> wrote in message > news:ms9cm8$leh$1@dont-email.me... > ... >> AFAICT, today we have string literals identifying things >> that can be called (Gtk), or we have selectors (Objective-C) >> for a similar thing, etc. A mouse click or gesture is thus >> another kind of event to which programmers might want to attach >> something that reacts. How would static type systems help, >> knowing that trying to make them help has allegedly failed >> in the past? > > I have no idea why you think this is a problem. Much like Objective-C is making use of C for implementing a rather flexible O-O PL, one could use Ada the same way, or one can use Ada's existing O-O features for implementing GUI style event handling programs. But this addresses the problem (GUI event driven programming, say) at the level of implementation, i.e. not directly. The language is not generally providing wishes to objects, for handling events of various sorts. Simply because Ada, like most languages I guess, doesn't address events in the language, except for a very few. These "events" can be mapped to problem domain events. Like objects dying, or signals handled in a PO, or file streams ending in an I/O exception. GUI programming is therefore just using general programming features for implementing callback style subprograms that involve objects. Programmers know the recommended ways, work is based on conventions. The model is implying the existence of some conventional run loop that operates using conventional means of the language. Events are implicit, not language. So, while there is no problem with either a very flexible O-O system emulated in C, or with having the Ada compiler help with earlier binding, both approaches do not handle events in the language. That's not a problem, but it is an opportunity, I think. > So I fail to see any problem that isn't being addressed here. Finalization > is a very special kettle of fish, because the objects don't exist > afterwards. It's needed to provide last wishes to objects, for clean-up of > various sorts. (For instance, Claw uses finalization to unhook windows from > the active window list, else we'd be calling actions on non-existent > windows. There is no other bullet-proof way to do that, if one wants there > library to work in the face of exceptions and abort, as well as programmer > mistakes [failing to call Close appropriately].) ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-04 7:33 ` Georg Bauhaus @ 2015-09-04 21:34 ` Randy Brukardt 2015-09-05 6:31 ` Dmitry A. Kazakov ` (3 more replies) 0 siblings, 4 replies; 31+ messages in thread From: Randy Brukardt @ 2015-09-04 21:34 UTC (permalink / raw) "Georg Bauhaus" <bauhaus@futureapps.invalid> wrote in message news:msbhc8$6qq$1@dont-email.me... ... > So, while there is no problem with > either a very flexible O-O system emulated in C, or with having the Ada > compiler help with earlier binding, both approaches do not handle events > in the language. I have not the slightest clue as to what "handling events in the language" would look like, assuming Ada doesn't have it. "Events" to me are just calls (dynamic control flow), and I don't see anything sensible that would make calls "better". Perhaps a lack of imagination on my part. > That's not a problem, but it is an opportunity, I think. Opportunity for what, madness? Event-driven GUI programming is just one step short of madness as it is, I'd hate to expand that. Such code is necessarily unstructured spaggetti, because every routine has to be able to handle anything in essentially any order. Much like OOP itself, I don't see it having much application away from the GUI (and I'm dubious that it is that good of an organization even for a GUI). As such, it doesn't make much sense in a general purpose programming language. Randy. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-04 21:34 ` Randy Brukardt @ 2015-09-05 6:31 ` Dmitry A. Kazakov 2015-09-05 6:44 ` Georg Bauhaus ` (2 subsequent siblings) 3 siblings, 0 replies; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-05 6:31 UTC (permalink / raw) On Fri, 4 Sep 2015 16:34:40 -0500, Randy Brukardt wrote: > Opportunity for what, madness? Event-driven GUI programming is just one step > short of madness as it is, I'd hate to expand that. Such code is necessarily > unstructured spaggetti, because every routine has to be able to handle > anything in essentially any order. There are competing relationships which do not map each other. An issuer-handler relationship is a mess because other relationship, the hierarchy of widget types, is considered more important. Another messy relationship is container-child. We cannot have all three structured, thus two of them are necessarily mess. > Much like OOP itself, I don't see it having much application away from the > GUI (and I'm dubious that it is that good of an organization even for a > GUI). GUI is a poor example for OO actually, because of above. > As such, it doesn't make much sense in a general purpose programming > language. Only OOP makes sense. There is *no* application where procedural decomposition is superior to OO decomposition. Procedural decomposition is untyped per design, because procedures can work with existing types only. Therefore you must have all types *before* you start thinking in terms of procedures. So the only types which can be involved are primitive scalar types or messy ad-hoc low-level records and arrays. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-04 21:34 ` Randy Brukardt 2015-09-05 6:31 ` Dmitry A. Kazakov @ 2015-09-05 6:44 ` Georg Bauhaus 2015-09-05 7:07 ` Dmitry A. Kazakov 2015-09-05 6:45 ` Niklas Holsti 2015-09-05 7:16 ` Shark8 3 siblings, 1 reply; 31+ messages in thread From: Georg Bauhaus @ 2015-09-05 6:44 UTC (permalink / raw) On 04.09.15 23:34, Randy Brukardt wrote: > Event-driven GUI programming is just one step > short of madness as it is, I'd hate to expand that. Such code is necessarily > unstructured spaggetti, because every routine has to be able to handle > anything in essentially any order. Unstructured spaghetti in O-O programs is the very thing that rings a bell. ;-) But I'd expect to see the same in unstructured procedural programs (of structured programming) and also in massively coupled equational definitions (of functionists' programs). It's common. There is an overabundance of attempts at addressing systematically one kind of event handling, viz. JavaScript based DOM events in client- server systems. Lots of frameworks to choose from, more or less mature; some nice ideas; some good old ideas. No universally accepted solution. (And nothing in the language, really, other than the names in addEventListener(event_name, function, ...).) Some questions that might frequently arise, I think: - How are the program's objects related when such-and-such happens? Can we express that in source text, specifically? - Are there any ways for correctly reacting to Pig_flies_By? E.g. topsorted orders of calls. Can we declare that set of orders in the source text, specifically? If, to find an answer, we are now looking at simulators, or at graphs drawn by some tool, or just study the sources and write memos. then these ways of explaining reactions to events seems to work only after the fact, not by declaration. Temporal logic is, I guess, one way of formalizing these relationships. Not that I'm fluent in it! ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-05 6:44 ` Georg Bauhaus @ 2015-09-05 7:07 ` Dmitry A. Kazakov 0 siblings, 0 replies; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-05 7:07 UTC (permalink / raw) On Sat, 5 Sep 2015 08:44:14 +0200, Georg Bauhaus wrote: > - How are the program's objects related when such-and-such happens? Individual relationships of objects is a recipe for mess. BTW, this is what is so wrong in OOA/D, which many wrongly equate to OO. > Can we express that in source text, specifically? Make a list of language mechanisms and go through it... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-04 21:34 ` Randy Brukardt 2015-09-05 6:31 ` Dmitry A. Kazakov 2015-09-05 6:44 ` Georg Bauhaus @ 2015-09-05 6:45 ` Niklas Holsti 2015-09-05 7:21 ` Dmitry A. Kazakov ` (3 more replies) 2015-09-05 7:16 ` Shark8 3 siblings, 4 replies; 31+ messages in thread From: Niklas Holsti @ 2015-09-05 6:45 UTC (permalink / raw) On 15-09-05 00:34 , Randy Brukardt wrote: > "Georg Bauhaus" <bauhaus@futureapps.invalid> wrote in message > news:msbhc8$6qq$1@dont-email.me... > ... >> So, while there is no problem with >> either a very flexible O-O system emulated in C, or with having the Ada >> compiler help with earlier binding, both approaches do not handle events >> in the language. > > I have not the slightest clue as to what "handling events in the language" > would look like, assuming Ada doesn't have it. It seems to me that Georg's "events" are rather like the "pointcuts" or "join points" in aspect-oriented programming (https://en.wikipedia.org/wiki/Aspect-oriented_programming) where some computation is added to certain points in a program without modifying the original source code, and instead coding the new computation separately and somehow declaratively defining how the original and new computations are interleaved at run-time at the join points. Ada has three features that are similar to this: controlled types, run-time constraint checks, and predicate checks. By making a type controlled, implicit calls of Initialize, Adjust, and Finalize are added at specific points (Georg's "events") in the program. By adding constraints to a type, or predicates to a type or operation, implicit checks ("calls") of those constraints and predicates are added at specific points in the program. However, in aspect-oriented programming the implicitly invoked, new computation is not meant to affect the original computation, but to implement some other linked computation, another aspect of the application. Aspect-oriented programming aims to let programmers define more such pointcuts/events and added computation, for application-specific purposes, and thereby isolate the different "aspects" of the program -- a new sort of modularity and separation of concerns. > "Events" to me are just calls > (dynamic control flow), and I don't see anything sensible that would make > calls "better". Perhaps a lack of imagination on my part. I have long wished for an easier way to return multiple results from a call, especially when the set of results that is really available depends on the run-time outcome of the call, for example on whether the called operation succeeded or failed in some way. At present, to return multiple results from a call, the callee either has to have multiple "out" parameters, or an "out" parameter that is a record type with multiple components. The caller then has to declare her own variables to stand as actual parameters, even if these variables are used only to receive the outputs of this call. If the set of available outputs depends on the outcome of the call, some of the "out" parameters, or some of the components of the "out" record, are often irrelevant and meaningless in some outcomes. For example, if a procedure that searches for an item based on a key fails to find the item, it must return both a "not found" status and an irrelevant, dummy item value. A variant-record "out" parameter can be used to hide the irrelevant item component in such cases, but this adds complexity to the declaration of the record type, and again it will often be the case that this record type is used only for this one procedure and its calls. I have vague ideas that it should be possible to declare, in a procedure's parameter profile, the various outcomes that are possible (found, not found, ...) and which outputs are available in which outcomes. Then it should be possible to call a procedure in a way that opens a block that implicitly starts with a case statement and separates into different branches for different outcomes, with the available "out" parameters directly accessible (as constant objects) in each branch without the caller having to declare her own local variables just for use as actual "outs". Alternatively, the outputs of the call could be implicitly organised like a variant record, with a designated output playing the role of discriminant and case selector. In addition to the variant-record (or class-wide) "out" parameter, Ada has two ways to implement such things: - Different outcomes of a procedure can be signalled by propagating an exception from the call, but this is an extreme all-or-nothing method: if an exception is propagated, the only output from the call is the identity of the exception (and possible side effects). - Outputs of a computation can be made available to a caller, without the caller having to declare "out" variables, by implementing the computation in the elaboration block in the body of a generic package, which has generic formal objects corresponding to the formal "in" and "in out" parameters of the computation, and declares public variables corresponding to the "out" parameters of the computation. To "call" this computation, the "caller" instantiates the generic, and can then access the public variables of the instance, with the values computed at elaboration of the instance, without explicitly declaring her own variables for use as "outs". But I'm sure that most programmers would consider this to be a weird misuse of the generic facility. Further, the instantiation must be done as a declaration, not as a statement, and the "out" variables can seldom be declared constant, because the computation is often too complex to be done in the declaration of the generic package. In a more functional-programming approach, a procedure could be made to "return" its outputs by calling different "continuation" procedures (given as "in" parameters) for the different outcomes; each such continuation procedure could have its own set of "in" parameters corresponding to the "outs" available from the original procedure in this outcome. This would be rather far from the procedural Ada style, but perhaps it could be used as the internal implementation of what I proposed above, even if the source syntax does not look like continuations. > Opportunity for what, madness? Event-driven GUI programming is just one step > short of madness as it is, Ooh, strong agreement here... but I don't think Georg means such events. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ . ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-05 6:45 ` Niklas Holsti @ 2015-09-05 7:21 ` Dmitry A. Kazakov 2015-09-05 12:07 ` Peter Chapin ` (2 subsequent siblings) 3 siblings, 0 replies; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-05 7:21 UTC (permalink / raw) On Sat, 5 Sep 2015 09:45:43 +0300, Niklas Holsti wrote: > - Outputs of a computation can be made available to a caller, without > the caller having to declare "out" variables, by implementing the > computation in the elaboration block in the body of a generic package, > which has generic formal objects corresponding to the formal "in" and > "in out" parameters of the computation, and declares public variables > corresponding to the "out" parameters of the computation. To "call" this > computation, the "caller" instantiates the generic, and can then access > the public variables of the instance, with the values computed at > elaboration of the instance, without explicitly declaring her own > variables for use as "outs". But I'm sure that most programmers would > consider this to be a weird misuse of the generic facility. Further, the > instantiation must be done as a declaration, not as a statement, and the > "out" variables can seldom be declared constant, because the computation > is often too complex to be done in the declaration of the generic package. It is worth to have a language construct for this. There are cases beyond multiple out parameters when this is necessary, e.g. if X in T'Class then declare Y : T'Class renames T'Class (X); or if Ptr /= null then declare X : T := Ptr.all; > In a more functional-programming approach, a procedure could be made to > "return" its outputs by calling different "continuation" procedures > (given as "in" parameters) for the different outcomes; each such > continuation procedure could have its own set of "in" parameters > corresponding to the "outs" available from the original procedure in > this outcome. This would be rather far from the procedural Ada style, > but perhaps it could be used as the internal implementation of what I > proposed above, even if the source syntax does not look like continuations. This is an independent case to me. It falls into the basket "co-routines". If we had co-routines we could use them to handle multiple outputs. BTW, this is rather data-driven approach than functional. DDA is a mess on a much bigger scale than one could imagine... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-05 6:45 ` Niklas Holsti 2015-09-05 7:21 ` Dmitry A. Kazakov @ 2015-09-05 12:07 ` Peter Chapin 2015-09-06 10:45 ` Georg Bauhaus 2015-10-13 19:57 ` Eryndlia Mavourneen 3 siblings, 0 replies; 31+ messages in thread From: Peter Chapin @ 2015-09-05 12:07 UTC (permalink / raw) In article <d4vhcnF9eulU1@mid.individual.net>, niklas.holsti@tidorum.invalid says... > I have long wished for an easier way to return multiple results from a > call, especially when the set of results that is really available > depends on the run-time outcome of the call, for example on whether the > called operation succeeded or failed in some way. Functional languages have thought about this. Most provide a way of defining a kind of variant record with very lightweight syntax so defining a new record for each use isn't onerous. As an example Scala (for instance) has an Option type in its library specifically for use by functions that may not have a valid value to return. A function that might or might not return an integer can be declared to run an Option[Int] (like a generic instance) that either holds the integer in question or has the special value None. This can be simulated in Ada without too much pain but what makes functional languages different is that it is easy to define and use variations of this idea without a lot of ceremony. > Then it should be possible to call a procedure in a way that opens a > block that implicitly starts with a case statement and separates into > different branches for different outcomes... This is done using pattern matching in functional languages which, as you observe, complements the features above very nicely. Actually Scala provides higher order methods on the Option type that allows you, in that case, to operate on data that might or might not be there without worrying about checking for its existence until the last minute. This pushes error handling out of the main logic of your program without using exceptions for that purpose. I'm not sure how possible it would be to retrofit these ideas into Ada. I'm going to guess it would be hard. Ada is not a functional language and as soon as you start walking down the path I'm talking about here you end up dragging in a lot of the usual functional machinery. Peter ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-05 6:45 ` Niklas Holsti 2015-09-05 7:21 ` Dmitry A. Kazakov 2015-09-05 12:07 ` Peter Chapin @ 2015-09-06 10:45 ` Georg Bauhaus 2015-10-13 19:57 ` Eryndlia Mavourneen 3 siblings, 0 replies; 31+ messages in thread From: Georg Bauhaus @ 2015-09-06 10:45 UTC (permalink / raw) On 05.09.15 08:45, Niklas Holsti wrote: > On 15-09-05 00:34 , Randy Brukardt wrote: >> "Georg Bauhaus" <bauhaus@futureapps.invalid> wrote in message >> news:msbhc8$6qq$1@dont-email.me... >> ... >>> So, while there is no problem with >>> either a very flexible O-O system emulated in C, or with having the Ada >>> compiler help with earlier binding, both approaches do not handle events >>> in the language. >> >> I have not the slightest clue as to what "handling events in the language" >> would look like, assuming Ada doesn't have it. > > It seems to me that Georg's "events" are rather like the "pointcuts" or "join points" in aspect-oriented programming (https://en.wikipedia.org/wiki/Aspect-oriented_programming) where some computation is added to certain points in a program without modifying the original source code, and instead coding the new computation separately and somehow declaratively defining how the original and new computations are interleaved at run-time at the join points. These "aspects" (of AOP) would come to mind, but rather than focus on them, I wanted to start from a more inclusive definition of "event", perhaps a little broader than those "aspects", but applicable to a number of programming situations. A definition that can lead the way to language for writing a program's reaction to specific "events". Summarily: Some words of source text would then express "event handling", but neither by way of having "_Handler" as the suffix of some primitive operation's name, nor by the event being an exception, say, and event handling being the statements of an exception handler. Exploring a bit: First and foremost, programmers need to be oriented when being asked about events and how their programs handle them, so that's an aspect to keep in mind when defining "event". If you think about both programming situations (involving humans) and also about programs that run (involving technology like clocks, mice, touch screens, networks, thermometers), then "event" becomes the name of quite many different ideas. However, they all share certain qualities: 1) that of being tied to one single point in space-time 2) that of having economic impact 3) that of being recurring problems in need of a solution ad 1) while (1) happens to agree with what dictionaries say, there is limited support for the property of being single in the Ada language. More so if there would be other sorts of things single, besides event handlers. The support that Ada offers is not addressing events in particular. (Ada is not unique here.) If there is a chance that some event requires a 1:1 mapping in the source text, or in the mind of a programmer being asked about it, then just a bit of general Ada language paired with conventions is all there is. ad 2), imagine a programmer needing to answer questions of the kind "What happens if A?". Can they just point at some place in the source text? What will they find, and how? I guess it is some table-like thing, or some more or less implicit connection of types. These two "traces" of event handling both would contain hints at the parts of the program involved in handling the event "A". Managing this "cross referencing structure" is tedious and costly. (No surprise that GUI programming is considered tricky; it is full of patterns.) If a program does not provide any of this (Gordian spaghetti), then long hours might pass until programmers can answer after studying their program once again. (I am assuming that a majority of GUI programs is not modeled after some real specification. Unfortunately.) Also, when developing a program that handles events, there is no specific guidance by the language; there are libraries that make use of some of the language's features. Of necessity, this creates idiosyncrasies. This state of the art might be good when selling proprietary class libraries, but engineers and project leaders may want something more standard for this very standard programming problem, lest they become "part of the business". (At whose cost?) ad 3) a "problematic" event is an easily named entity; like whenever input channel X14 is delivering data, the program's behavior should be such-and-such, possibly depending further on such-and-such. Or behavior is unexpected. Now, in general,Without these events, many programs would be pointless. Still, language-wise, solutions aren't directly available: programmers rely on class libraries or similar. But solutions need to be found again and again, so as to have programs that handle anything at all. In case of unexpected behavior, solving the problem means modifying the program. But how, if someone else has written the program and used this or that convention? Tasks to the rescue? What can you learn from a task's interface that you couldn't learn from a type's interface? There is one additional bit, viz. independent execution. Does it help event handling? Not according to Aaron Hillegass, who explains that many activities seen to be concurrent can actually be handled conveniently by programming to the run-loop. (I believe some OS design guys also suggest non-communicating processes, but don't remember the name of their project.) A last idea: GUI design programs are a visualization of some event handling, Or rather, they show the stage for event handling. But either way, somehow events are present there. So, GUI design programs use somewhat formal definitions of how objects should be tied together for handling events. They produce some manifestations of "event handling". Is this kind of formalization inaccessible to programming languages? ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-05 6:45 ` Niklas Holsti ` (2 preceding siblings ...) 2015-09-06 10:45 ` Georg Bauhaus @ 2015-10-13 19:57 ` Eryndlia Mavourneen 3 siblings, 0 replies; 31+ messages in thread From: Eryndlia Mavourneen @ 2015-10-13 19:57 UTC (permalink / raw) On Saturday, September 5, 2015 at 1:45:45 AM UTC-5, Niklas Holsti wrote: > I have long wished for an easier way to return multiple results from a > call, especially when the set of results that is really available > depends on the run-time outcome of the call, for example on whether the > called operation succeeded or failed in some way. Sounds just like the Icon programming language, a derivative and elaboration of SNOBOL/SPITBOL. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-04 21:34 ` Randy Brukardt ` (2 preceding siblings ...) 2015-09-05 6:45 ` Niklas Holsti @ 2015-09-05 7:16 ` Shark8 3 siblings, 0 replies; 31+ messages in thread From: Shark8 @ 2015-09-05 7:16 UTC (permalink / raw) On Friday, September 4, 2015 at 3:34:43 PM UTC-6, Randy Brukardt wrote: > "Georg Bauhaus" wrote in message > > That's not a problem, but it is an opportunity, I think. > > Opportunity for what, madness? Event-driven GUI programming is just one step > short of madness as it is, I'd hate to expand that. But what about Ada's Task (and protected objects) -- aren't the rendezvous-mechanisms EXACTLY event-driven? > Much like OOP itself, I don't see it having much application away from the > GUI (and I'm dubious that it is that good of an organization even for a > GUI). As such, it doesn't make much sense in a general purpose programming > language. Well, if you consider that MVC is a design-pattern for GUIs, you could do the same sort of separation "on the other side" letting the model essentially be the interface between the buisness-logic-layer and either of the GUI/DB layer... and on the DB side of the interface you could directly map "save model X" to the appropriate DB call. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-03 11:39 ` G.B. 2015-09-03 12:00 ` G.B. @ 2015-09-03 13:47 ` Dmitry A. Kazakov 1 sibling, 0 replies; 31+ messages in thread From: Dmitry A. Kazakov @ 2015-09-03 13:47 UTC (permalink / raw) On Thu, 3 Sep 2015 13:39:22 +0200, G.B. wrote: > On 03.09.15 11:26, Dmitry A. Kazakov wrote: >> On Thu, 3 Sep 2015 10:14:35 +0200, Georg Bauhaus wrote: >> >> An object of a type is *same* in all contexts, because the type is same. > > While an object doesn't change either identity or type, > it does changes state. This is an event, too. Yes, but according to that definition finalization is not an event. After finalization the object is in no state. >> 2. Regarding finalization, another crucial point. Finalization is *not* an >> operation. > > I'm not asking for finalization as an operation. > I'm asking for clearly defined hooks made for operations > (or something else) for what programmers will now put into > Finalize, since there is nothing else where to put it. Hook is OK except that if spelled as an operation there is a danger of being called explicitly. Which is why a syntax sugar of a body without interface would be much preferable. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-02 10:59 Top 10 Worst C# Features Stefan.Lucks 2015-09-02 17:37 ` Álex R. Mosteo 2015-09-02 19:39 ` Randy Brukardt @ 2015-09-03 8:51 ` gautier_niouzes 2015-10-01 14:03 ` Paul Colin de Gloucester 3 siblings, 0 replies; 31+ messages in thread From: gautier_niouzes @ 2015-09-03 8:51 UTC (permalink / raw) Le mercredi 2 septembre 2015 13:09:47 UTC+2, Stefan...@uni-weimar.de a écrit : > The remaining eight C# issues have been solved in Ada. For those not fluent in both languages, it would be useful to develop these points, IMHO. _________________________ Gautier's Ada programming http://gautiersblog.blogspot.com/search/label/Ada NB: follow the above link for a valid e-mail address ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-09-02 10:59 Top 10 Worst C# Features Stefan.Lucks ` (2 preceding siblings ...) 2015-09-03 8:51 ` gautier_niouzes @ 2015-10-01 14:03 ` Paul Colin de Gloucester 2015-10-14 8:00 ` Maciej Sobczak 3 siblings, 1 reply; 31+ messages in thread From: Paul Colin de Gloucester @ 2015-10-01 14:03 UTC (permalink / raw) On September 2nd, 2015, Steven Lucks sent: |------------------------------------------------------------------------| |"[. . .] | | | |In Ada, the "/="-operator is automatically the negation of "=". Which is| |great. [. . .] | |[. . .] | | | |[. . .]" | |------------------------------------------------------------------------| One of the bugs which I detected in Crap-Poo-Poo code which I referred to in the paper referred to below involved two functions like these, but they accidentally did not return values compatible with each other. I explained this to Crap-Poo-Poo advocates involved, but they lacked sufficient intelligence to comprehend a reason as to code cloning producing a bug. I also advised that Ada does not do this. They persisted with Crap Poo Poo. @article{ author = {{de Gloucester}, Paul Colin}, title = {{Referees Often Miss Obvious Errors in Computer and Electronic Publications}}, journal = {Accountability in Research: Policies and Quality Assurance}, volume = {20}, year = {2013}, pages = {143--166}, number = {3} } ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-01 14:03 ` Paul Colin de Gloucester @ 2015-10-14 8:00 ` Maciej Sobczak 2015-10-14 14:26 ` Ben Bacarisse 2015-11-06 14:50 ` Nicholas Collin Paul de Gloucester 0 siblings, 2 replies; 31+ messages in thread From: Maciej Sobczak @ 2015-10-14 8:00 UTC (permalink / raw) > One of the bugs which I detected in Crap-Poo-Poo code which I referred > to in the paper referred to below involved two functions like these, > but they accidentally did not return values compatible with each > other. I explained this to Crap-Poo-Poo advocates involved, but they > lacked sufficient intelligence to comprehend a reason as to code > cloning producing a bug. Apparently you have talked to wrong advocates. For the sake of discussion I will play that role in this post. Yes, we understand that it is possible to have incompatible implementations of operator== and operator!= in C++ (assuming that this is the language you are referring to), but we are willing to take this risk (and address it by other means) as it allows us to implement these operators more efficiently. One possible example where this could be possible is when the encapsulated data has a digital signature or some other short digest available with the property that when two digests are different then the objects are surely different (and this can be determined very quickly), whereas when the digests are equal then more work is needed to determine whether the objects are equal, too. In this case, our operator!= can be much faster than operator== and we are willing to benefit from the optimization opportunity here. This could not be possible if one is automatically derived from the other. > I also advised that Ada does not do > this. Yes, we know that Ada prevents some optimization strategies. This is not the only one. > They persisted with Crap Poo Poo. Yes, we prefer to get better performance at the expense of higher verification effort. If you are willing to address the above, please use the actual name of the programming language that you are referring to. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 8:00 ` Maciej Sobczak @ 2015-10-14 14:26 ` Ben Bacarisse 2015-10-14 16:50 ` Paul Rubin 2015-10-15 12:24 ` Maciej Sobczak 2015-11-06 14:50 ` Nicholas Collin Paul de Gloucester 1 sibling, 2 replies; 31+ messages in thread From: Ben Bacarisse @ 2015-10-14 14:26 UTC (permalink / raw) Maciej Sobczak <see.my.homepage@gmail.com> writes: <snip> > Yes, we understand that it is possible to have incompatible > implementations of operator== and operator!= in C++ (assuming that > this is the language you are referring to), but we are willing to take > this risk (and address it by other means) as it allows us to implement > these operators more efficiently. Do you mean that there are reasons to permit !(a == b) and a != b to have different values in some cases? I don't think you mean this (because your example does not obviously address that possibility), but I am not 100% sure. > One possible example where this could be possible is when the > encapsulated data has a digital signature or some other short digest > available with the property that when two digests are different then > the objects are surely different (and this can be determined very > quickly), whereas when the digests are equal then more work is needed > to determine whether the objects are equal, too. In this case, our > operator!= can be much faster than operator== and we are willing to > benefit from the optimization opportunity here. This could not be > possible if one is automatically derived from the other. I don't see why bool operator!=(const T &other) const noexcept { if (this.hash != other.hash) return true; return !this.long_slow_equality_test(other); } is any more or less efficient than bool operator==(const T &other) const noexcept { if (this.hash != other.hash) return false; return this.long_slow_equality_test(other); } but I may have missed the point you are trying to make. <snip> -- Ben. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 14:26 ` Ben Bacarisse @ 2015-10-14 16:50 ` Paul Rubin 2015-10-14 18:17 ` Stefan.Lucks 2015-10-15 12:24 ` Maciej Sobczak 1 sibling, 1 reply; 31+ messages in thread From: Paul Rubin @ 2015-10-14 16:50 UTC (permalink / raw) Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > Do you mean that there are reasons to permit !(a == b) and a != b to > have different values in some cases? I think he meant they should both return the same value, but it is ok if they don't use the same algorithm. Of course it may be possible for the compiler to optimize the first into the second. The idea is just that if (a != b) { ... } can be much faster than if (a == b) { ... } . ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 16:50 ` Paul Rubin @ 2015-10-14 18:17 ` Stefan.Lucks 2015-10-14 19:54 ` Ben Bacarisse 0 siblings, 1 reply; 31+ messages in thread From: Stefan.Lucks @ 2015-10-14 18:17 UTC (permalink / raw) [-- Attachment #1: Type: text/plain, Size: 2394 bytes --] On Wed, 14 Oct 2015, Paul Rubin wrote: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >> Do you mean that there are reasons to permit !(a == b) and a != b to >> have different values in some cases? > > I think he meant they should both return the same value, but it is ok if > they don't use the same algorithm. Of course it may be possible for the > compiler to optimize the first into the second. The idea is just that > if (a != b) { ... } can be much faster than if (a == b) { ... } . As I seem to understand, Ben questioned that either the test on equality or on non-equality could be much faster than the other one. In Ada syntax: function "="(A, B: T) return Boolean is begin if Hash(A) /= Hash(B) then return False else return Slow_Equality_Test(A, B) end "="; function "/="(A, B: T) return Boolean is begin if Hash(A) /= Hash(B) then return True else return Not Slow_Equality_Test(A, B) end "/="; -- if this where allowed in Ada It seems quite clear that for any inputs X and Y, the expressions X = Y and X /= Y should evaluate at the same speed. Or what am I missing? Actually, "/=" could be faster than "=" if either where defined as follows: function "="(A, B: T) return Boolean renames Slow_Equality_Test; function "/="(A, B: T) return Boolean is (Hash(A) /= Hash(B)); -- second case Redefining "=" this way is just missing an optimization. Redefining "/=" is that way is a bug. So how could "/=" really be faster than "="? My guess is that the devil's advocate, Maciej Sobczak, assumed that "=" is already in use as identifier, instead of another identifier for the Slow_Equality_Test, as I call it. Which means, we cannot employ the optimization for equality. An independent "/=" would then allow us to optimize non-equality. But this would be a design flaw, and it might be easy to fix: function "="(A, B: T) return Boolean is -- optimized equality begin if Hash(A) /= Hash(B) then return False else return Outer_Package."="(A, B) end "="; -------- I love the taste of Cryptanalysis in the morning! -------- www.uni-weimar.de/de/medien/professuren/mediensicherheit/people/stefan-lucks ----Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany---- ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 18:17 ` Stefan.Lucks @ 2015-10-14 19:54 ` Ben Bacarisse 0 siblings, 0 replies; 31+ messages in thread From: Ben Bacarisse @ 2015-10-14 19:54 UTC (permalink / raw) Stefan.Lucks@uni-weimar.de writes: > On Wed, 14 Oct 2015, Paul Rubin wrote: > >> Ben Bacarisse <ben.usenet@bsb.me.uk> writes: >>> Do you mean that there are reasons to permit !(a == b) and a != b to >>> have different values in some cases? >> >> I think he meant they should both return the same value, but it is ok if >> they don't use the same algorithm. Of course it may be possible for the >> compiler to optimize the first into the second. The idea is just that >> if (a != b) { ... } can be much faster than if (a == b) { ... } . > > As I seem to understand, Ben questioned that either the test on > equality or on non-equality could be much faster than the other one. Yes, exactly. If !(a == b) and a != b don't have to be the same for this imagined type then of course one can be faster than the other, but if the usual laws are to hold, implementing one can't be anything but trivially easier then the other. <snip> -- Ben. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 14:26 ` Ben Bacarisse 2015-10-14 16:50 ` Paul Rubin @ 2015-10-15 12:24 ` Maciej Sobczak 2015-10-15 13:59 ` Ben Bacarisse 1 sibling, 1 reply; 31+ messages in thread From: Maciej Sobczak @ 2015-10-15 12:24 UTC (permalink / raw) > Do you mean that there are reasons to permit !(a == b) and a != b to > have different values in some cases? Why not? We are already talking about the language where a+b is not necessarily equal to b+a (hint: strings). ;-) There is also an interesting area for objects that might be neither "equal" nor "different" (that is, where both operators might return false at the same time). As an illustration, Apples and Oranges are neither equal nor different, even though they are all Fruits and might be modeled in a flat type system. Of course, diverting from the usual laws is asking for trouble, but as I have already said - some programmers might be willing to get some added flexibility at the expense of higher verification effort. Definitely, one should not automatically assume that all C++ programmers are morons. > I don't see why > > bool operator!=(const T &other) const noexcept > { > if (this.hash != other.hash) > return true; > return !this.long_slow_equality_test(other); > } > > is any more or less efficient than > > bool operator==(const T &other) const noexcept > { > if (this.hash != other.hash) > return false; > return this.long_slow_equality_test(other); > } > > but I may have missed the point you are trying to make. No, but you have missed the point that I tried to address. Your example is OK with regard to performance, but for some reason you have still used *distinct* implementations of these operators, instead of calling one from another. And interestingly, your WCET is even worse than in my example, as it might need to execute two comparisons (fast and slow) instead of just the one which is asked for. Of course, I don't claim that these are typical usage scenarios. Typically, these operators indeed should be based on common logic. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-15 12:24 ` Maciej Sobczak @ 2015-10-15 13:59 ` Ben Bacarisse 0 siblings, 0 replies; 31+ messages in thread From: Ben Bacarisse @ 2015-10-15 13:59 UTC (permalink / raw) Maciej Sobczak <see.my.homepage@gmail.com> writes: >> Do you mean that there are reasons to permit !(a == b) and a != b to >> have different values in some cases? > > Why not? We are already talking about the language where a+b is not > necessarily equal to b+a (hint: strings). ;-) I asked because I wanted to know the context for the remark that prompted my reply. That remark was In this case [when there is a hash or signature], our operator!= can be much faster than operator== and we are willing to benefit from the optimization opportunity here. <snip> >> I don't see why >> >> bool operator!=(const T &other) const noexcept >> { >> if (this.hash != other.hash) >> return true; >> return !this.long_slow_equality_test(other); >> } >> >> is any more or less efficient than >> >> bool operator==(const T &other) const noexcept >> { >> if (this.hash != other.hash) >> return false; >> return this.long_slow_equality_test(other); >> } >> >> but I may have missed the point you are trying to make. > > No, but you have missed the point that I tried to address. Your > example is OK with regard to performance, but for some reason you have > still used *distinct* implementations of these operators, instead of > calling one from another. No, I've just given an example of both because I disputed this remark: In this case [when there is a hash or signature], our operator!= can be much faster than operator== and we are willing to benefit from the optimization opportunity here. There is no reason at all to use both, but the easiest way to explain why I find the claim hard to accept is to show both. In practice, either one will do with the other implemented as the negation of the one chosen. You claimed that the case you gave (where the objects have a hash or signature that allows for rapid non-equality testing) was an example where separate implementations of != and == would be advantageous, but what you described is not enough for the conclusion to hold. That's why I asked about !(a != b) == (a == b). <snip> -- Ben. ^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: Top 10 Worst C# Features 2015-10-14 8:00 ` Maciej Sobczak 2015-10-14 14:26 ` Ben Bacarisse @ 2015-11-06 14:50 ` Nicholas Collin Paul de Gloucester 1 sibling, 0 replies; 31+ messages in thread From: Nicholas Collin Paul de Gloucester @ 2015-11-06 14:50 UTC (permalink / raw) On October 14th, 2015, Maciej Sobczak sent: |-------------------------------------------------------------------------| |"> One of the bugs which I detected in Crap-Poo-Poo code which I referred| |> to in the paper referred to below involved two functions like these, | |> but they accidentally did not return values compatible with each | |> other. I explained this to Crap-Poo-Poo advocates involved, but they | |> lacked sufficient intelligence to comprehend a reason as to code | |> cloning producing a bug. | | | |Apparently you have talked to wrong advocates. | |For the sake of discussion I will play that role in this post. | | | |Yes, we understand that it is possible to have incompatible | |implementations of operator== and operator!= in C++ (assuming that | |this is the language you are referring to), but we are willing to | |take this risk (and address it by other means) as it allows us to | |implement these operators more efficiently. | |[. . .]" | |-------------------------------------------------------------------------| This Crap-Poo-Poo code was inefficient. The idea of an operator which is a complement of another operator being implemented in terms of a complementary operator had not occurred to these idiots. |-------------------------------------------------------------------------| |"> I also advised that Ada does not do | |> this. | | | |Yes, we know that Ada prevents some [. . .]. This is not the only one." | |-------------------------------------------------------------------------| Ada prevents bugs. |-------------------------------------------------------------------------| |"> They persisted with Crap Poo Poo. | | | |Yes, we prefer to get better performance at the expense of higher | |verification effort." | |-------------------------------------------------------------------------| Actually, they untruthfully boasted about both being faster and being verified. |-------------------------------------------------------------------------| |"If you are willing to address the above, please use the actual name | |of the programming language that you are referring to. | | | |-- | |Maciej Sobczak * http://www.inspirel.com " | |-------------------------------------------------------------------------| Why? It was supposedly in C++ (which one of the aforementioned idiots frequently used to accidentally call C then) and supposedly SystemC(R) code. Note that persons who impose a requirement on how to use the SystemC(R) name do not even adhere to this requirement themselves. Regards, Nicholas Collin Paul de Gloucester ^ permalink raw reply [flat|nested] 31+ messages in thread
end of thread, other threads:[~2015-11-06 14:50 UTC | newest] Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-09-02 10:59 Top 10 Worst C# Features Stefan.Lucks 2015-09-02 17:37 ` Álex R. Mosteo 2015-09-02 19:39 ` Randy Brukardt 2015-09-03 8:14 ` Georg Bauhaus 2015-09-03 9:26 ` Dmitry A. Kazakov 2015-09-03 11:39 ` G.B. 2015-09-03 12:00 ` G.B. 2015-09-03 13:59 ` Dmitry A. Kazakov 2015-09-03 19:12 ` Randy Brukardt 2015-09-04 7:33 ` Georg Bauhaus 2015-09-04 21:34 ` Randy Brukardt 2015-09-05 6:31 ` Dmitry A. Kazakov 2015-09-05 6:44 ` Georg Bauhaus 2015-09-05 7:07 ` Dmitry A. Kazakov 2015-09-05 6:45 ` Niklas Holsti 2015-09-05 7:21 ` Dmitry A. Kazakov 2015-09-05 12:07 ` Peter Chapin 2015-09-06 10:45 ` Georg Bauhaus 2015-10-13 19:57 ` Eryndlia Mavourneen 2015-09-05 7:16 ` Shark8 2015-09-03 13:47 ` Dmitry A. Kazakov 2015-09-03 8:51 ` gautier_niouzes 2015-10-01 14:03 ` Paul Colin de Gloucester 2015-10-14 8:00 ` Maciej Sobczak 2015-10-14 14:26 ` Ben Bacarisse 2015-10-14 16:50 ` Paul Rubin 2015-10-14 18:17 ` Stefan.Lucks 2015-10-14 19:54 ` Ben Bacarisse 2015-10-15 12:24 ` Maciej Sobczak 2015-10-15 13:59 ` Ben Bacarisse 2015-11-06 14:50 ` Nicholas Collin Paul de Gloucester
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox