Mozilla have lost their mind - Part 2



  • so the first couple paragraphs translate to: Activator.CreateInstance(Type.GetType("typeAsString"));

    and the middle couple paragraphs translate to:

    <FONT size=2 face=Consolas><FONT size=2 face=Consolas></FONT></FONT><FONT color=#0000ff size=2 face=Consolas><FONT color=#0000ff size=2 face=Consolas><FONT color=#0000ff size=2 face=Consolas><FONT size=2 face=Consolas><FONT size=2 face=Consolas>

    sourceList.OfType<S>().ToList();</FONT></FONT></FONT></FONT></FONT>

    <FONT size=2 face=Consolas>You're not making a good case as to why any of that stuff is useful.  Forget the Sapir-Whorf hypothesis.  TELL ME what it's good for.</FONT>



  • @BC_Programmer said:

    Most of the Delphi language as it is today was not created by him; many concepts that might be attributed to his hand are really quite "obvious" features to design into a modern language.

    Yes, from a modern perspective, 15 years later looking back, they certainly are.  Back then? Not so much.

    @Mason Wheeler said:
    Can you take the type returned by GetType and call a virtual method on it?  Can you use it in a factory style by taking a type reference and calling a constructor?


    The first case can be done using reflection; creating the instance would require either calling Activator.CreateInstance() and passing the appropriate Type to the method (and constructor arguments as an array) or, by calling the appropriate ConstructorInfo acquired from the Type; this ConstructorInfo can be acquired by using GetConstructor() and passing the appropriate arguments, which include the ability to have an array of Type['s that define the parameters of the constructorInfo you want. Calling that constructorInfo, which gives you the constructed object. You can even create new Type objects from Generic Types by providing the Type Arguments to CreateGenericType().

    Wow, that's a lot of work you have to do just to work around the lack of class references!

    @Mason Wheeler said:
    A clear separation of interface from implementation, giving you a simple, clean overview of what each class can do without wading through screens full of code, is "no good reason"?


    That's the problem. There was no "separation"- it's no different than C/C++ header files, where you need to state the function declaration in the header, and then state it again when you implement it.

    The difference is that in Delphi you don't have two separate source files to keep track of.

    If you want to separate the interface from the implementation, you use an interface. With the Delphi method, the implementation and the interface were "strongly coupled" at the source-code level.

    You're splitting hairs here.  If you create an Interface and a class that implements it, and then you change the definition of the Interface, you have to also change the class(es) that implement it accordingly, or it won't compile.  The exact same coupling exists here; there's just a new layer of indirection involved.

    From my understanding the original requirement in pascal to have the interface presented before the implementation was as much a decision to allow to make it easier to parse the code as it was stylistic; in fact, I suspect it was the former passed off as the latter on an ad hoc basis.

    I won't deny that.  It's definitely a big part of what makes the Delphi compiler so incredibly fast.  But it also helps keep your code clean and easy to read.  Win-win situation.

    @Mason Wheeler said:
    All of those features you just mentioned are present in Delphi.


    Yes, NOW they are... but a good question is, for how long? There is a good chance they were implemented after C#... and if not, than after java, in which case we can only surmise that Borland had abducted James Gosling. As for reflection: the only Delphi I know of that has reflection is Delphi.NET, in which case it's using the reflection inherent in the CLR and the Framework, and is not a language feature. RTTI is not the direct equivalent to Reflection; Reflection seems, from what I can tell, to be RTTI and Metaclasses rolled into one to a degree, and what's left I suspect to be covered, if only partially, by the functionality of generics.

    Take a look at the new extended RTTI functionality introduced in Delphi 2010.

    I'm not sure what you find so bad about the Delphi IDE.  It's got some severe problems with CodeInsight (their version of Intellisense,) but that can be disabled pretty easily, and aside from that it's wonderful to work with.


    my problem is it never works; in fact, that was why I stopped using Delphi and switched back to VB6, despite the lesser language features of VB6. Not sure which version it was. Each time I've tried to get the latest version it either refuses to install, doesn't install properly, or crashes rather infrequently. I suspect I have simply been unlucky, but it still embittered me towards the product.

    Well, you didn't know about extended RTTI, so I'm going to make a completely wild guess and say that you probably haven't tried it anytime in the last 3 years or so?  In Delphi 8 (2004 release) they decided to rework a lot of things and got most of them very, very wrong.  The whole IDE was a mess and a half until the 2009 release, so I can't blame you for thinking the IDE was crap if you tried the latest version sometime during those years.  It really was.  But they've mostly got it fixed now, with CodeInsight and a few related features being the glaring exception.

    Also, There is simply no free IDE I can use; for .NET I could use SharpDevelop or MonoDevelop, for exampl.

    I agree, this is a problem. I've been one of the strongest advocates in the Delphi community for a free version.  They recently released a "Starter Edition" that's not free, but it's a lot less expensive than it has been in the past, though.  That's a start, but hopefully they'll take it further in the future.

    This wouldn't be so bad, but the IDE (again, for me, and was not the latest version) crashes somewhat infrequently.

    Stability has improved dramatically in the last few releases.  Once the team got out from under Borland and had people who actually cared about the product in charge once again, things got a lot better very quickly.  You should give it another look.

    In particular, its debugger and its form designer are what Visual Studio's versions of the same want to be like when they grow up.


    have you even used Visual Studio lately?

    Yes, 2005, 2008 and 2010, and trying to debug in them is *painful* because they're either completely missing basic features I take for granted in Delphi, or they're implemented in strange and unintuitive ways, or getting at them is much harder than it needs to be.

     



  • @Sutherlands said:

    so the first couple paragraphs translate to: Activator.CreateInstance(Type.GetType("typeAsString"));

    Yeah.  This is what's known as an abstraction inversion.  You need an "Activator" and a bunch of messy, slow reflection stuff because the language doesn't allow you to implement it as a simple, straightforward function call like any other.  (How would you use an Activator to invoke a constructor that takes parameters, for example?  Is there any way to do it that ensures type correctness at compile time?)

    and the middle couple paragraphs translate to:

    <font face="Consolas" size="2"><font face="Consolas" size="2"></font></font><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font face="Consolas" size="2"><font face="Consolas" size="2"> </font></font></font></font></font>

    <font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font face="Consolas" size="2"><font face="Consolas" size="2">sourceList.OfType<S>().ToList();

    </font></font></font></font></font>

    And how would you do it before LINQ and generics were invented? Because this is really fundamental stuff that's been available since Delphi 1.

    <font face="Consolas" size="2">

    You're not making a good case as to why any of that stuff is useful.  Forget the Sapir-Whorf hypothesis.  TELL ME what it's good for.</font>

    That's the thing.  All the really simple examples that can be easily entered in a discussion thread can probably also be done with either LINQ or Attributes.  And the more complicated ones are difficult to explain if you don't already have enough background that you know why they're useful.

    Here's one, though, an example from our program at work.  It's been around for a while, since back before the term "ORM" became fashionable.  We've got a homegrown object/database mapping system, in which all data classes descend from a certain base class that implements the basic database functionality.  The base class has a virtual class method called GetQuery, which returns "'select * from ' + GetTableName;".  (After retrieving this, another routine generates the WHERE clause.)

    GetTableName is also a virtual abstract class method.  It could easily be replaced by an Attribute, but Attributes weren't available (in Delphi or .NET) back when they built the system. But since GetTableName is declared abstract, the compiler will warn you if you create and try to use a descendant class that doesn't override it.  You don't get that kind of check with Attributes.  GetQuery, though, can't really be replaced by an Attribute.  Some of our more complex classes have very large, complicated queries that need to be generated at runtime according to various rules.  So a function is really the only way to set them up.

    These can't be made into instance methods, because nothing gets instantiated until the results come back from the database.  All we have is a class reference that gets passed into the ORM so it knows what sort of data it's supposed to be retrieving.  It calls the virtual GetQuery method to obtain the data, queries the database, grabs the results, instantiates the objects by calling the virtual constructor, and stuffs the data into them, with no need for Generics (which also didn't exist in either Delphi or .NET back when this was written) or Activators.

     



  • @Mason Wheeler said:

    Yes, from a modern perspective, 15 years later looking back, they certainly are.  Back then? Not so much.
     

     

    A lot of the features present in Delphi 2 (if we are to go by the 1996/15 years ago thing) were present in other languages. It wasn't just the language features, but how it was coupled into a RAD tool that made it a good platform. Most of the other languages implementing such features were "backwater" type languages that nobody really used outside academia. Many of the features weren't "new" in the sense of being absolutely new language features, but rather language features "taken" from other languagesand implemented into Delphi, and made those features more accessible for serious development. I'm not 100% sure that Delphi was the first to do that, but I'm fairly sure it was. And if not, it was really close.

     @Mason Wheeler said:

    Wow, that's a lot of work you have to do just to work around the lack of class references!

    If necessary it can be made rather trivial by adding helper Extension methods. My point is more or less that the features of Delphi that you can't live without are mostly syntactic sugar, and can be reproduced in other languages. It's also a lot shorter than the explanation, code-wise. However, I've made several rather large C# projects and I haven't thought to use any feature like those described. They seem more like useful language features to use when available but I don't see how their absence can be game-breaking to anybody except those who have become dependent on them. Sort of how People don't need Crack to live but an addict may feel otherwise- because they have grown psychologically or physiologically dependent on it.

     as for the version I used, 2004 sounds about right. To be fair though, I think you are giving me way to much credit- I wasn't even able to bother developing any non-trivial applications before giving up on the IDE; The reason I didn't know about Extended RTTI at the time wasn't necessarily because it was lacking from the language as much as I was practically starting from scratch based on my even earlier experiences with Turbo Pascal 6.

     

    @Mason Wheeler said:

    Yes, 2005, 2008 and 2010, and trying to debug in them is *painful* because they're either completely missing basic features I take for granted in Delphi, or they're implemented in strange and unintuitive ways, or getting at them is much harder than it needs to be. 

    I think that's more an artifact of you trying to do it the "Delphi way". I have no doubt that when or if I give the newer Delphi product a try I'll find things implemented in what I feel the be strange and unintuitive ways. This is how it always feels when I try a new IDE- this includes when I moved to Visual Studio 2005 from Visual Basic 6 (finally). Some things were the same, some things were different, and it felt like I was "in somebody elses kitchen" so to speak, until I got used to it, and now when I have to maintain a VB6 application it feels like I've gone back to the kitchen of an old house that now belongs to somebody else. Either way, I think I may have to give the latest version a go; particularly if it offers any sort of interoperability with .NET, since then I could implement various plugins for my current applications by way of Delphi. And even if it doesn't- it never hurts to become proficient in another language.



  • @BC_Programmer said:

    Either way, I think I may have to give the latest version a go; particularly if it offers any sort of interoperability with .NET, since then I could implement various plugins for my current applications by way of Delphi.
     

    Not out of the box, (unless you're using COM interop, of course, which would make it trivial,) but RemObjects has a .NET/Delphi plugin framework called Hydra what makes that kind of stuff very simple.

     



  • @Mason Wheeler said:

    and the middle couple paragraphs translate to:

    <font face="Consolas" size="2"><font face="Consolas" size="2"></font></font><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font face="Consolas" size="2"><font face="Consolas" size="2">
    </font></font></font></font></font>

    <font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font color="#0000ff" face="Consolas" size="2"><font face="Consolas" size="2"><font face="Consolas" size="2">sourceList.OfType<S>().ToList();

    </font></font></font></font></font>

    And how would you do it before LINQ and generics were invented? Because this is really fundamental stuff that's been available since Delphi 1.

    Here is how I would do it. My C# is rusty and self taught so there might be errors

    TypeList Filter(TypeList source,Type ty)
    {
        TypeList out_list =new TypeList();
        foreach(Type t in source)
        {
               if(t.IsSubClassOf(ty))
                  out_list.add(t);
        }
    return out_list;
    }
    


  • Who cares whether it was around in 2000?  How is that valid?  And what class are you loading so much that the speed of reflection becomes an issue?

    For your GetTableName, why do you say "with no need for Generics"?  You say that like they're a bad thing.

    Also, you can do all that through LINQ to SQL.

     

    Also, what delta said.



  • Could a mod fix my code formatting. I ran out of time trying to remember the html to fix it.

    mode: PRE tags, silly. :* -dh



  • @Sutherlands said:

    Who cares whether it was around in 2000? How is that valid?

    That's the classic Lotus Notes argument, when they're trapped in a corner. "Well, Lotus Notes may suck, but in 1990 it was the best email platform available!". As if that's relevant.

    Mason Wheeler in this thread is some kind of uber-Linux/Delphi/Microsoft-hating troll. I'm honestly somewhat impressed at how much he's sucking people in long after it became apparent he's either a complete idiot, or acting like one. He's spazzing out so fast it's hard to even pin him down. You question his credentials on office application GUI design, and he switches to game controllers. You point out the Xbox 360 controller doesn't suck, he flies on over to Delphi and starts spouting insane conspiracy theories*. You corner him by proving Delphi is a piece of shit**, and he'll flip over to, I dunno, ranting about how inferior Windows Phone 7 is or some shit. If I could predict it, I'd pre-empt it!

    Mason Wheeler, the power is yours!

    *) And what a shocking conspiracy theory is was: Microsoft hires experts at computer language design to design a new computer language! GASP! Call Sherlock Holmes!
    **) And when your last post's strongest defense is "hey guys the IDE doesn't crash quite as much anymore!" you're pretty much out of fuel on that one, buddy.



  • @blakeyrat said:

    Mason Wheeler in this thread is some kind of uber-Linux/Delphi/Microsoft-hating troll. I'm honestly somewhat impressed at how much he's sucking people in long after it became apparent he's either a complete idiot, or acting like one. He's spazzing out so fast it's hard to even pin him down.

    Simply because you're not able to follow a conversation as it shifts from one topic to another doesn't mean anyone else in this thread has that problem.

    Mason Wheeler, the power is yours!

    *eyeroll* Yeah, like I've never heard that one before...

    **) And when your last post's strongest defense is "hey guys the IDE doesn't crash quite as much anymore!" you're pretty much out of fuel on that one, buddy.
     

    See what I mean about what someone does when they have no valid argument?  I didn't say "hey guys the IDE doesn't crash quite as much anymore," I said it's solid now.  As in, for the last few releases, it does not crash.  (Not that it crashed all that much back when it was really crappy, either.  What it did do was leak tons of memory and get really slow.  But the recent versions don't do that anymore either.)

    If you've got anything actually constructive to say, by all means, please say it.  Otherwise, please make good on your promise earlier to leave this topic alone.

     



  • @Sutherlands said:

    And what class are you loading so much that the speed of reflection becomes an issue?

    All sorts of things.  The big ones are form deserialization and data access, sometimes pulling back data sets containing thousands or (in extreme cases) tens of thousands of rows.  If these operations execute slowly, (especially the form deserialization,) the user will notice and it will impact their perception of the quality of your program.

     



  • @Mason Wheeler said:

    @Sutherlands said:

    so the first couple paragraphs translate to: Activator.CreateInstance(Type.GetType("typeAsString"));

    Yeah.  This is what's known as an abstraction inversion.  You need an "Activator" and a bunch of messy, slow reflection stuff because the language doesn't allow you to implement it as a simple, straightforward function call like any other.  (How would you use an Activator to invoke a constructor that takes parameters, for example?  Is there any way to do it that ensures type correctness at compile time?)

     First: the Activator static methods are in fact wrappers around the functionality of Reflection that is built in that allows you to instantiate objects from a ConstructorInfo invocation. I already described how you would invoke a constructor requiring parameters; pass them to the CreateInstance() method. It has about a dozen Overloads. SOme of which allow you to create an instance directly from an Assembly name and it's Type name.Type correctness at compile time is not something you can do. I think there may be confusion here; Reflection seems to be most usable when loading, say, external libraries as plugins, or enumerating your own assembly to find all implementations of a given interface or all Type's that derive from a given base class; at that point, you have the Type variable for those types and you know they are of the base class type, and thus you can "enforce" type correctness by using the base type to store the object when you create it. (After which you can treat it just as you would any old instance of that base class).

    And how would you do it before LINQ and generics were invented? Because this is really fundamental stuff that's been available since Delphi 1.

    First- it's rather convenient to make such claims that nobody else can independently verify very easily. Delphi 1 is damn near impossible to get a hold of unless you happen to still have a copy. Delphi 1 was powerful for it's time but you are acting like all these features implemented into later languages, like C#, where "pioneered" by something in Delphi. Arguably, they may have been- looking at the code you provided, it seems that the Create "constructor" could just be a Static class method that returns the constructed object. derived classes in C# can override methods and indicate the return value as a class that derives from the return type of the virtual method which they override. Additionally if you want to be compatible with "Delphi 1.0", I'm fairly sure it didn't have proper iterators until a later version.Either way, whether a language happened to implement something first is meaningless. Because, from what I've seen from your samples, a lot of the features you are plugging on are present in C# (and .NET as a whole) but using different semantics. All this time I thought metaclasses where some new concept that was impossible to use in C# when judging from your examples it's simply a subset of generics. Even assuming this feature was available in Delphi 1, it was still "beaten" by C++ Templates, which were released before it. That doesn't make the C++ implementation any better in the same way that the Delphi implementation having been added earlier makes it's implementation better. All I can see now is somebody arguing over which brand of syntactic sugar is preferable under the guise that their way is better and using seeming specious arguments that the constructs are "fundamental". In a way, I sort of agree, particularly since almost all the features you've described so far have a functional equivalent in many other language, even if implementation might not have the sugary syntactic sweetness you are used to (but that can of course be changed with extension methods). Saying  "what would you do if there was no LINQ/Generics" is basically saying "Ok, so those features are better or at least feature equivalent to what I'm using, but what if you didn't have those, huh? then would you have any way of being as productive as me?" It's admitting that those features you have been plugging along with as if they were Delphi Unique do in fact have equivalents in other languages. I could just as easily say "oh yeah, well we have LINQ/Generics!", you say "but delphi has metaclasses", and then I argue "but what if Delphi DIDN'T have metaclasses?". It's a moot point- it does have metaclasses, conjuring up hypothetical situations that suit your side of a discussion is an argument to irrelevance. You can't just pretend the features of a language don't exist, because they DO exist, and they are being used. I personally didn't use C# before Generics/LINQ, but I can state with some certainty that without those features there is still a way to do the same thing. Just because it's not as terse as your godlike Delphi code doesn't automatically make it inferior. After all, almost every feature you find in Delphi is implemented in Python, and then some.

     

     

    All the really simple examples that can be easily entered in a discussion thread can probably also be done with either LINQ or Attributes.  And the more complicated ones are difficult to explain if you don't already have enough background that you know why they're useful.

    Well isn't that convenient for you then. Either way, I have no doubt that whatever these "more complicated" examples do, their functionality can be duplicated in C#. For all we know there is a feature in C# that I or other C# programmers use everyday that does the exact same thing and we aren't understanding because  we don't think of it that way.

    Here's one, though, an example from our program at work.  It's been around for a while, since back before the term "ORM" became fashionable.  We've got a homegrown object/database mapping system, in which all data classes descend from a certain base class that implements the basic database functionality.  The base class has a virtual class method called GetQuery, which returns "'select * from ' + GetTableName;".  (After retrieving this, another routine generates the WHERE clause.)

    GetTableName is also a virtual abstract class method.  It could easily be replaced by an Attribute, but Attributes weren't available (in Delphi or .NET) back when they built the system. But since GetTableName is declared abstract, the compiler will warn you if you create and try to use a descendant class that doesn't override it.  You don't get that kind of check with Attributes.  GetQuery, though, can't really be replaced by an Attribute.  Some of our more complex classes have very large, complicated queries that need to be generated at runtime according to various rules.  So a function is really the only way to set them up.

    Interesting. Why is it that you think this same functionality couldn't be had with a different design that doesn't use those features? Everything can be refactored, and really, If you want to have overrideable static-type methods (in C#) you should probably go with either A singleton, if you want the same subclass to be used globally, or a traditional class hierarchy, with a factory or dependency injection, if you want different behavior in different parts of your application.

     By the way- you might want to stop referring to .NET in the context of .NET being a language. Makes you look silly.

     

    All sorts of things.  The big ones are form deserialization and data access, sometimes pulling back data sets containing thousands or (in extreme cases) tens of thousands of rows.  If these operations execute slowly, (especially the form deserialization,) the user will notice and it will impact their perception of the quality of your program.

    I fail to understand how a row cannot be represented with a concrete type.

     


  • Considered Harmful

    @BC_Programmer said:

    Because, from what I've seen from your samples, a lot of the features you are plugging on are present in C# (and .NET as a whole) but using different semantics. All this time I thought metaclasses where some new concept that was impossible to use in C# when judging from your examples it's simply a subset of generics. Even assuming this feature was available in Delphi 1, it was still "beaten" by C++ Templates, which were released before it. That doesn't make the C++ implementation any better in the same way that the Delphi implementation having been added earlier makes it's implementation better. All I can see now is somebody arguing over which brand of syntactic sugar is preferable under the guise that their way is better and using seeming specious arguments that the constructs are "fundamental". In a way, I sort of agree, particularly since almost all the features you've described so far have a functional equivalent in many other language, even if implementation might not have the sugary syntactic sweetness you are used to (but that can of course be changed with extension methods). Saying  "what would you do if there was no LINQ/Generics" is basically saying "Ok, so those features are better or at least feature equivalent to what I'm using, but what if you didn't have those, huh? then would you have any way of being as productive as me?" It's admitting that those features you have been plugging along with as if they were Delphi Unique do in fact have equivalents in other languages. I could just as easily say "oh yeah, well we have LINQ/Generics!", you say "but delphi has metaclasses", and then I argue "but what if Delphi DIDN'T have metaclasses?". It's a moot point- it does have metaclasses, conjuring up hypothetical situations that suit your side of a discussion is an argument to irrelevance. You can't just pretend the features of a language don't exist, because they DO exist, and they are being used. I personally didn't use C# before Generics/LINQ, but I can state with some certainty that without those features there is still a way to do the same thing. Just because it's not as terse as your godlike Delphi code doesn't automatically make it inferior. After all, almost every feature you find in Delphi is implemented in Python, and then some.



  • @BC_Programmer said:

    @Mason Wheeler said:

    Yeah.  This is what's known as an abstraction inversion.  You need an "Activator" and a bunch of messy, slow reflection stuff because the language doesn't allow you to implement it as a simple, straightforward function call like any other.  (How would you use an Activator to invoke a constructor that takes parameters, for example?  Is there any way to do it that ensures type correctness at compile time?)

     First: the Activator static methods are in fact wrappers around the functionality of Reflection that is built in that allows you to instantiate objects from a ConstructorInfo invocation. I already described how you would invoke a constructor requiring parameters; pass them to the CreateInstance() method. It has about a dozen Overloads. SOme of which allow you to create an instance directly from an Assembly name and it's Type name.Type correctness at compile time is not something you can do.

    Exactly.   You take something that really ought to be simple--invoking a constructor as a function call like any other--and turn it into a big mess involving dynamic invocation and reflection, with no compiler assistance to verify type correctness.  Don't get me wrong; I have nothing against reflection. It's very useful in solving some difficult problems.  But that's really what it should be used for: difficult problems.  Not simple, fundamental things like a Factory Pattern implementation.  Anders Hejlsberg is reported to have said "static where possible, dynamic when necessary," and that's a very good principle.  It's a shame C# doesn't hold to it in this case.

    looking at the code you provided, it seems that the Create "constructor" could just be a Static class method that returns the constructed object.

    From that single example, you might think so, but no.  Constructors aren't class methods, and they aren't instance methods.  (And they're certainly not static methods, which--again--are not the same thing as class methods.)  Constructors are constructors, and they're unique in their semantics in that they can be invoked with class method syntax or with instance method syntax and each version will behave differently.   If you say "class.Create" it behaves as a function that returns a new instance of that class, while "instance.Create" behaves as a procedure that simply executes the code inside the constructor on an already-instantiated object without initializing a new one.  (And they don't have to be named "Create" either; that's just convention.)

    derived classes in C# can override methods and indicate the return value as a class that derives from the return type of the virtual method which they override.

    Yes, but if you want to call a virtual method in C#, you need to have an instance of the class first, because there are no virtual class methods.  That's the main point I'm trying to make here: that not needing to have an instance available before you can call virtual methods allows for a lot of extra flexibility, especially if you're trying to customize what ends up being created before you instantiate it.

    Either way, whether a language happened to implement something first is meaningless. Because, from what I've seen from your samples, a lot of the features you are plugging on are present in C# (and .NET as a whole) but using different semantics.

    Fair enough. If you follow that line of reasoning far enough you eventually reach the concept of Turing-equivalence.  But some languages make certain things a lot simpler than others.

    All this time I thought metaclasses where some new concept that was impossible to use in C# when judging from your examples it's simply a subset of generics.

    Not really.  Yes, there's some overlap in what they can do, but class references and generics are really two completely different concepts.

    Even assuming this feature was available in Delphi 1, it was still "beaten" by C++ Templates, which were released before it. That doesn't make the C++ implementation any better in the same way that the Delphi implementation having been added earlier makes it's implementation better.

    Oy. Don't even get me started on Templates.  Probably the worst implementation of generics in any language ever.  Definitely the worst in any I'm familiar with.

    All I can see now is somebody arguing over which brand of syntactic sugar is preferable under the guise that their way is better and using seeming specious arguments that the constructs are "fundamental". In a way, I sort of agree, particularly since almost all the features you've described so far have a functional equivalent in many other language, even if implementation might not have the sugary syntactic sweetness you are used to (but that can of course be changed with extension methods).

    That's the thing.  Class references are not "syntactic sugar" by any meaning of the word I'm familiar with.  They're a fundamental primitive data type, implemented as a simple pointer to a class's VMT.  Syntactic sugar means taking something that can be done in a complicated way and adding a syntactic construct to the language that does the same thing in the same complicated way but without you having to type out all the details.

    For example, instead of writing:

    enumerator := collection.GetEnumerator;
    while enumerator.MoveNext do
    begin
      value := enumerator.GetCurrent;
      //do something with the value
    end;

    you can reduce that to two lines:

    for value in collection do
      //do something with the value

    A for-in loop (or a simple for loop, for that matter) is sytactic sugar.  It still ends up doing semantically exactly what I wrote in the first example, but you don't have to type all that out every time. But that has nothign to do with class references and how they work.

    Saying  "what would you do if there was no LINQ/Generics" is basically saying "Ok, so those features are better or at least feature equivalent to what I'm using, but what if you didn't have those, huh? then would you have any way of being as productive as me?" It's admitting that those features you have been plugging along with as if they were Delphi Unique do in fact have equivalents in other languages. I could just as easily say "oh yeah, well we have LINQ/Generics!", you say "but delphi has metaclasses", and then I argue "but what if Delphi DIDN'T have metaclasses?". It's a moot point- it does have metaclasses, conjuring up hypothetical situations that suit your side of a discussion is an argument to irrelevance. You can't just pretend the features of a language don't exist, because they DO exist, and they are being used.

    Sorry. I guess my point is that doing these things in C# requires much more complicated solutions that took several versions before they got around to implementing them, because they're stuff the language was never really designed to do.  And LINQ and Generics are both really complicated stuff. (Especially LINQ!)  The engineer in me looks at these soutions and shudders.  A good rule of thumb is "never use a more complicated solution when a lower-tech one is available."  Less things that can go wrong that way, and when something does go wrong, it's easier to fix.

    Just because it's not as terse as your godlike Delphi code doesn't automatically make it inferior.

    I never said anything about terseness.  While it can certainly be useful in moderation, I find that excessive brevity often detracts significantly from code readability and thus from code quality.

    After all, almost every feature you find in Delphi is implemented in Python, and then some.

    Let's not even go there.  Python is a completely different paradigm with its own set of strengths and weaknesses, and to be frank, OOP is one of its weaknesses.

    Everything can be refactored, and really, If you want to have overrideable static-type methods (in C#) you should probably go with either A singleton, if you want the same subclass to be used globally, or a traditional class hierarchy, with a factory or dependency injection, if you want different behavior in different parts of your application.

    I'm sorry. Maybe it's just that it's getting late, but that makes no sense at all.  I know what the words and concepts mean, but used together like that it all just adds up to something unintelligible. :(

    By the way- you might want to stop referring to .NET in the context of .NET being a language. Makes you look silly.

    No, I said exactly whatI meant: that these features were not available in .NET.  As in, they were not available in any .NET language because they required feature support from the CLR that did not exist yet.

    All sorts of things.  The big ones are form deserialization and data access, sometimes pulling back data sets containing thousands or (in extreme cases) tens of thousands of rows.  If these operations execute slowly, (especially the form deserialization,) the user will notice and it will impact their perception of the quality of your program.

    I fail to understand how a row cannot be represented with a concrete type. 

    Again, what you say makes no sense.  I never said that a row can't be represented with a concrete type. What I said is that the data still has to be transferred from the row returned by the query result to the concrete type (object) that's representing it, and if that happens slowly, the user will notice and will think that your product sucks, which is why you want to avoid anything inherently slow (such as reflection) when doing this.

     



  • @Mason Wheeler said:

    ...The IDE doesn't suck...

    Ok, first let me tell you this, I liked PASCAL when I was young and stuff and for a time used TurboPascal so I'm not that biased against Delphi.

    The last time I installed Delphi was version 6 I think and let me tell you the IDE and the documentation was crap...

    So yesterday I installed a more modern version, Delphi2009 (yes, I know there is a newer one but I won't buy it sorry, this one I got from a buddy)

    So.. I played with it for a bit, to be fair I'll continue playing with it to get a more accurate feel for it but my impresion so far is

    1. The documentation is way better than older versions but still not better than Visual Studio, even if you compare it to VS2008
    2. The IDE is still ugly crap, but so far not extremely buggy crap, I mean wtf, it look the same, ok, intellisense is better and we got color differentiation (thanks god for that), the only issue I had so far was that the compiler marked a piece of autogenerated code as not declared but when compiled it runned ok (wtf)

     I'll keep at it but if your point was that Embarcadero makes better software than Microsoft, so far I can't agree.

    If your point is that C# took stuff from languages including Delphi sure, almost every language is like that however I doubt there is a conspiracy

    Now if you are claiming that Delphi is superior than c#, hmm I can't say until I try Delphi a lot but I doubt it.

    I'll keep you posted



  • You know what?

    This thread is in desperate need for some mini-nukes.



  • @Xyro said:


    You know what?

    This thread is in desperate need for some mini-nukes.

    How about a terrifying clown face?

    Oh shit wrong image. Oh well.



  • @Mason Wheeler said:

    All sorts of things.  The big ones are form deserialization and data access, sometimes pulling back data sets containing thousands or (in extreme cases) tens of thousands of rows.  If these operations execute slowly, (especially the form deserialization,) the user will notice and it will impact their perception of the quality of your program.

    I fail to understand how a row cannot be represented with a concrete type. 

    Again, what you say makes no sense.  I never said that a row can't be represented with a concrete type. What I said is that the data still has to be transferred from the row returned by the query result to the concrete type (object) that's representing it, and if that happens slowly, the user will notice and will think that your product sucks, which is why you want to avoid anything inherently slow (such as reflection) when doing this.

    I asked what you used type info for so many times, you provided data access as an example.  You don't need that.  A row can be represented by a concrete type.  If you're using reflection when processing rows....



  • I think his problem is that he is so used to doing things the Delphi way he cannot wrap his head around doing it differently.



  • @Sutherlands said:

    @Mason Wheeler said:

    All sorts of things.  The big ones are form deserialization and data access, sometimes pulling back data sets containing thousands or (in extreme cases) tens of thousands of rows.  If these operations execute slowly, (especially the form deserialization,) the user will notice and it will impact their perception of the quality of your program.

    I fail to understand how a row cannot be represented with a concrete type. 

    Again, what you say makes no sense.  I never said that a row can't be represented with a concrete type. What I said is that the data still has to be transferred from the row returned by the query result to the concrete type (object) that's representing it, and if that happens slowly, the user will notice and will think that your product sucks, which is why you want to avoid anything inherently slow (such as reflection) when doing this.

    I asked what you used type info for so many times, you provided data access as an example.  You don't need that.  A row can be represented by a concrete type.  If you're using reflection when processing rows....

    That doesn't solve the problem; it just pushes it back a step.  So instead of transferring the query results from the result set to a collection of data objects, you just simply keep them in a collection of generic row result objects.  That'll work just fine if all you need to do is bind it to a grid in the UI or something, but if you need to process the data, you'll have to deal with individual values (columns) from the rows of that result set.  Which means you need some sort of "Row.ColumnValueByName" method, which requires some sort of string-based lookup.  If you have to do that every time, things are going to bog waaaaaaaay down on larger datasets.  That's the whole reason why you transfer everything into data objects upfront: to avoid all the slow dynamic lookup stuff every time you need to access the data.

    If this feels like "doing it wrong" to someone steeped in C# idioms, then no wonder .NET programs have a reputation for being slow!  I never thought I'd find myself agreeing with Paul Graham, but this whole subthread is practically a perfect illustration of the "Blub paradox."

     



  • @Mason Wheeler said:

    Which means you need some sort of "Row.ColumnValueByName" method, which requires some sort of string-based lookup.

    That's in the C# standard framework. If you're writing it yourself, (cue cat picture).

    @Mason Wheeler said:

    If you have to do that every time, things are going to bog waaaaaaaay down on larger datasets.

    We trust Microsoft to do it right, and they do.

    @Mason Wheeler said:

    If this feels like "doing it wrong" to someone steeped in C# idioms, then no wonder .NET programs have a reputation for being slow!

    Wha...?

    I've never heard of this "reputation." I've heard "bloated" (due to the large runtime/framework), but I've never heard "slow".

    @Mason Wheeler said:

    I never thought I'd find myself agreeing with Paul Graham, but this whole subthread is practically a perfect illustration of the "Blub paradox."

    His (and your) mindset is completely ass-backwards. The most important priority for a language is to be easy-to-read. The second is probably to be inter-operable with other languages, via similar syntax and via being able to share functions in shared libraries and such. "Powerful" is way down the list.



  • @blakeyrat said:

    @Mason Wheeler said:
    Which means you need some sort of "Row.ColumnValueByName" method, which requires some sort of string-based lookup.

    That's in the C# standard framework. If you're writing it yourself, (cue cat picture).

    I didn't say it requires you to write one yourself, just that it requires you to use one, and that any string-based lookup, (even one implemented with a hash table) will inevitably be a good deal slower than direct, static access to the properties of an object.

    @Mason Wheeler said:
    If you have to do that every time, things are going to bog waaaaaaaay down on larger datasets.

    We trust Microsoft to do it right, and they do.

    ...if you say so.

    @Mason Wheeler said:
    If this feels like "doing it wrong" to someone steeped in C# idioms, then no wonder .NET programs have a reputation for being slow!

    Wha...?

    I've never heard of this "reputation." I've heard "bloated" (due to the large runtime/framework), but I've never heard "slow".

    Really?  Those are the most common complaints I hear about .NET programs.  Bloated (large framework dependency), bloated (high memory requirements at runtime) and slow.

    The most important priority for a language is to be easy-to-read.

    I agree completely.  And in that area, Pascal beats C-anything hands down.

    The second is probably to be inter-operable with other languages, via similar syntax and via being able to share functions in shared libraries and such.

    "Similar syntax" isn't really all that useful unless you want to write polyglots; that just ends up tripping you up when there are unexpected differences hidden in the similarities.  Shared libraries, on the other hand, are quite beneficial, and again Delphi's got a huge advantage here: it can share with any native library without the need for any marshalling or P/Invoke.  In fact, it's actually better at talking to C-based DLLs than C is!  Not to mention the simplest, most straightforward COM implementation around.  Microsoft may have invented COM, but it's the folks at Borland who truly understood it.

    "Powerful" is way down the list.

    ...which is why so many programs I have to use are crap.  They're written by people with that attitude.  Please do the whole world a favor and don't ever teach a newbie how to write code.

     



  • @blakeyrat said:

    @Mason Wheeler said:
    Which means you need some sort of "Row.ColumnValueByName" method, which requires some sort of string-based lookup.
    That's in the C# standard framework. If you're writing it yourself, (cue cat picture). @Mason Wheeler said:
    If you have to do that every time, things are going to bog waaaaaaaay down on larger datasets.
    We trust Microsoft to do it right, and they do. @Mason Wheeler said:
    If this feels like "doing it wrong" to someone steeped in C# idioms, then no wonder .NET programs have a reputation for being slow!
    Wha...?

    I've never heard of this "reputation." I've heard "bloated" (due to the large runtime/framework), but I've never heard "slow". @Mason Wheeler said:

    I never thought I'd find myself agreeing with Paul Graham, but this whole subthread is practically a perfect illustration of the "Blub paradox."
    His (and your) mindset is completely ass-backwards. The most important priority for a language is to be easy-to-read. The second is probably to be inter-operable with other languages, via similar syntax and via being able to share functions in shared libraries and such. "Powerful" is way down the list.

    I agree with this... my first impression of c# back when it was released was that it was so clean and easy to read and somewhat verbose, it is one of the things I actually liked from the start.

     "easy to read" is an awesome thing to have

    Ok, if you need to copy stuff and you need it really fast you can always use http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

    Ohh, I have heard that c# programs are bloated or slow but that is mostly overexageration or people being dicks people.  Yes there are some extreme situation where a software doing critical stuff might benefit from a couple microseconds gained but most of the time that is not the case and the the things that c# brings to the table far outweight this.



  • @Mason Wheeler said:

    ...which is why so many programs I have to use are crap.

    What does the power of the programming language have to do with the crappiness of the resulting program? Honestly asking-- I see no link there at all.

    Also, how much does Embarcadero pay you?



  • @Mason Wheeler said:

    @blakeyrat said:

    @Mason Wheeler said:
    Which means you need some sort of "Row.ColumnValueByName" method, which requires some sort of string-based lookup.
    That's in the C# standard framework. If you're writing it yourself, (cue cat picture).

    I didn't say it requires you to write one yourself, just that it requires you to use one, and that any string-based lookup, (even one implemented with a hash table) will inevitably be a good deal slower than direct, static access to the properties of an object.

    Now you're just talking in circles.  No, we C# programmers do not keep data rows in a generic row of result objects.  (Well, some do, namely my predecessors, but the good ones don't.)  We don't need reflection to get data out of a data row.  We don't need meta-information.  Here's pseudo-code for what we do:

    public GetAccounts(string param1) {

      using([...] DataReader.ExecuteStoredProc("sp_name", param1) {

        while(reader.Read()) {

          Object o = new Object();

          o.Property = reader["property"];

          objectList.Add(o);}}

      return objectList;}

    For super-large datasets, performance can be increased by getting the index of "property" in the set and using that.  Perfectly reasonable code, perfectly understandable way.  Don't need "virtual constructors".

     

    Also, forgive me for not believing that Delphi is better at talking to C DLLs than C, based on someone who says "I really have no clue what it is or why it’s necessary.  I’ve never had to deal with them before."  Sounds like you found yourself an expert.



  • @blakeyrat said:

    @Mason Wheeler said:
    ...which is why so many programs I have to use are crap.

    What does the power of the programming language have to do with the crappiness of the resulting program? Honestly asking-- I see no link there at all.

    First off, let me be absolutely clear that I have a very different definition of "powerful" WRT programming languages than Paul Graham does.  To me, a powerful language is one that makes writing good code easier.  (Which does not mean one that makes writing bad code harder; I've never seen any evidence that any such language exists.)  A powerful language is one that makes the actions produced by execution of code most closely match what you would expect from reading it.  (Principle of Least Surprise and all that.)  A powerful language is one that makes it easy to read and discern the intent of code, even when written by someone else, because the majority of development time is spent on maintenance, not implementation.  And a powerful language is one with the power to do many different things well, to reach both the high and the low end of the abstraction spectrum.  A language that creates baseline abstractions and provides no way to get beneath them when necessary is just as crippled as a language that is missing important high-level features.

    Understanding that, the link between the power of the language and the quality of programs written in it should be clear.  A powerful language makes it easy to produce high-quality programs. And Delphi is the most powerful language I'm familiar with.  It's not some sort of religious devotion for me or anything like that.  If I found a better language, I would use it instead.  But so far, I haven't.

    Also, how much does Embarcadero pay you?

    As cool as it would be to be a professional Delphi advocate, or maybe a member of the team, that is not the case.  There are other forms of self-interest besides the financial variety.  I'm a computer user as well as a computer programmer, and I want more people writing programs in Delphi because it makes writing good code easier, and tends to produce software that works well, which means I end up having to use less software that's crap.

     



  • @Mason Wheeler said:

    First off, let me be absolutely clear that I have a very different definition of "powerful" WRT programming languages than Paul Graham does.  To me, a powerful language is one that makes writing good code easier.  (Which does not mean one that makes writing bad code harder; I've never seen any evidence that any such language exists.)  A powerful language is one that makes the actions produced by execution of code most closely match what you would expect from reading it.  (Principle of Least Surprise and all that.)  A powerful language is one that makes it easy to read and discern the intent of code, even when written by someone else, because the majority of development time is spent on maintenance, not implementation.  And a powerful language is one with the power to do many different things well, to reach both the high and the low end of the abstraction spectrum.  A language that creates baseline abstractions and provides no way to get beneath them when necessary is just as crippled as a language that is missing important high-level features.

    It sounds like your priorities are in-line with mine, and with the C# team's. So I wonder why you rail against it so.

    @Mason Wheeler said:

    Understanding that, the link between the power of the language and the quality of programs written in it should be clear.

    Well it's not. Your first paragraph is great, but you never got around to telling us what any of it has to do with the quality of the program.

    @Mason Wheeler said:

    A powerful language makes it easy to produce high-quality programs.

    Maybe it does; but it also makes it easy to produce shitty programs. Yes?

    @Mason Wheeler said:

    It's not some sort of religious devotion for me or anything like that.

    With you, I think it might actually be.

    @Mason Wheeler said:

    As cool as it would be to be a professional Delphi advocate, or maybe a member of the team, that is not the case.

    Well then stop it, because you're being a complete bore.



  • @Sutherlands said:

    Now you're just talking in circles.  No, we C# programmers do not keep data rows in a generic row of result objects.  (Well, some do, namely my predecessors, but the good ones don't.)  We don't need reflection to get data out of a data row.  We don't need meta-information.  Here's pseudo-code for what we do:

    public GetAccounts(string param1) {

      using([...] DataReader.ExecuteStoredProc("sp_name", param1) {

        while(reader.Read()) {

          Object o = new Object();

          o.Property = reader["property"];

          objectList.Add(o);}}

      return objectList;}

    For super-large datasets, performance can be increased by getting the index of "property" in the set and using that.  Perfectly reasonable code, perfectly understandable way.  Don't need "virtual constructors".

    OK, I'm completely lost here.  By Object do you mean Object, the base class from which all objects descend?  If not, what do you mean?  And how do you deal with having more than one type of data being returned ("select * from table1" vs. "select * from table2") where both result sets have more than one column?  It looks to me like you're glossing over a whole lot of details in order to make it look like C# can do magic.  I don't believe in magic.

    Also, forgive me for not believing that Delphi is better at talking to C DLLs than C, based on someone who says "I really have no clue what it is or why it’s necessary.  I’ve never had to deal with them before."  Sounds like you found yourself an expert.
     

    The "someone" was me; that's from my blog.   And the "no clue what it is" is rhetoric; that should be apparent if you read the next paragraph, where it explains exactly what the .lib file is, why it's necessary on C, and why Delphi doesn't require it.

     



  • @Mason Wheeler said:

    @Sutherlands said:

    Now you're just talking in circles.  No, we C# programmers do not keep data rows in a generic row of result objects.  (Well, some do, namely my predecessors, but the good ones don't.)  We don't need reflection to get data out of a data row.  We don't need meta-information.  Here's pseudo-code for what we do:

    public GetAccounts(string param1) {

      using([...] DataReader.ExecuteStoredProc("sp_name", param1) {

        while(reader.Read()) {

          Object o = new Object();

          o.Property = reader["property"];

          objectList.Add(o);}}

      return objectList;}

    For super-large datasets, performance can be increased by getting the index of "property" in the set and using that.  Perfectly reasonable code, perfectly understandable way.  Don't need "virtual constructors".

    OK, I'm completely lost here.  By Object do you mean Object, the base class from which all objects descend?  If not, what do you mean?  And how do you deal with having more than one type of data being returned ("select * from table1" vs. "select * from table2") where both result sets have more than one column?  It looks to me like you're glossing over a whole lot of details in order to make it look like C# can do magic.  I don't believe in magic.

    You must have missed the word "pseudo-code".  Object is whatever object you're trying to populate.  Property is whatever property you're trying to populate.  Why do you have more than one type of data in a single table?  Why not return multiple tables?  If, in your example, the multiple selects returns multiple tables in one result set, i would separate out the tables.  That much seems obvious.  If for some reason there just HAS to be 2 types of data in one table, and assuming again that there is a column that specifies the type (since that would be what you pass to your "virtual constructor"), I would create a method for each unique type to create an object based on a datarow, and then call that method based on what was in that column.


    Also, forgive me for not believing that Delphi is better at talking to C DLLs than C, based on someone who says "I really have no clue what it is or why it’s necessary.  I’ve never had to deal with them before."  Sounds like you found yourself an expert.
     

    The "someone" was me; that's from my blog.   And the "no clue what it is" is rhetoric; that should be apparent if you read the next paragraph, where it explains exactly what the .lib file is, why it's necessary on C, and why Delphi doesn't require it.

    Then forgive me for not believing it based on you.  Sounds like you found yourself an expert.

    Also, thought we were talking about C#?



  • @blakeyrat said:

    @Mason Wheeler said:
    First off, let me be absolutely clear that I have a very different definition of "powerful" WRT programming languages than Paul Graham does.  To me, a powerful language is one that makes writing good code easier.  (Which does not mean one that makes writing bad code harder; I've never seen any evidence that any such language exists.)  A powerful language is one that makes the actions produced by execution of code most closely match what you would expect from reading it.  (Principle of Least Surprise and all that.)  A powerful language is one that makes it easy to read and discern the intent of code, even when written by someone else, because the majority of development time is spent on maintenance, not implementation.  And a powerful language is one with the power to do many different things well, to reach both the high and the low end of the abstraction spectrum.  A language that creates baseline abstractions and provides no way to get beneath them when necessary is just as crippled as a language that is missing important high-level features.

    It sounds like your priorities are in-line with mine, and with the C# team's. So I wonder why you rail against it so.

    Because C# fails on several points.  It's C-based syntax is difficult to read, and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,) and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.

    @Mason Wheeler said:
    Understanding that, the link between the power of the language and the quality of programs written in it should be clear.

    Well it's not. Your first paragraph is great, but you never got around to telling us what any of it has to do with the quality of the program.

    @Mason Wheeler said:

    A powerful language makes it easy to produce high-quality programs.

    That is the link.  How can you miss it?

    Maybe it does; but it also makes it easy to produce shitty programs. Yes?

    Irrelevant, unless you can show me a language that makes it difficult to produce bad programs.  (And no, trotting out Malbolge, INTERCAL or something similarly ridiculous that makes it difficult to produce any programs at all is cheating.)  I've never seen any (serious) programming language that makes it difficult to write bad code.  I don't think such a thing exists, or can exist.



  • @Sutherlands said:


    Also, forgive me for not believing that Delphi is better at talking to C DLLs than C, based on someone who says "I really have no clue what it is or why it’s necessary.  I’ve never had to deal with them before."  Sounds like you found yourself an expert.
     

    The "someone" was me; that's from my blog.   And the "no clue what it is" is rhetoric; that should be apparent if you read the next paragraph, where it explains exactly what the .lib file is, why it's necessary on C, and why Delphi doesn't require it.

    Then forgive me for not believing it based on you.  Sounds like you found yourself an expert.

    Also, thought we were talking about C#?

    He is trying to convert us to the joys of Delphi and is throwing things out there on how it is better somehow. I am tempted to spend some time learning C++ template metaprogramming just to spite him. Now watch as he goes of on C++ next


  • @Mason Wheeler said:

    It's C-based syntax is difficult to read,

    "Its", and personal opinion.  I find C# extremely easy to read.

    and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)
    Hardly game-breaking even if it were true, and the different versions do different things... one short-circuits and one doesn't.  How are those two not needed?

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.
    Example?

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.
    How is a string in C# more complicated than it needs to be?  Also, that "bug" is "literally impossible" without having running as trusted code.  Which is why you don't run unknown dlls in full-trust.



  • @Sutherlands said:

    You must have missed the word "pseudo-code".

    No, that's just way too "pseudo" to actually demonstrate anything useful.

    Object is whatever object you're trying to populate.  Property is whatever property you're trying to populate.

    Yeah.  "Property," singular.  That's where the example breaks down. If I had a method called "GetAccounts," for example, that queried the database, it would almost certainly return a data set consisting of several different columns. (Name: string; Address: string; Balance: currency, etc...)  This requires multiple distinct properties on the Account objects in order to represent the data.  How are you mapping multiple columns to multiple properties?

    Why do you have more than one type of data in a single table?  Why not return multiple tables?

    Sorry, I guess it wasn't clear what I'm asking. What I meant was, how do you get this code to correctly process individual queries to more than one different table, at different times?  Or do you have multiple different routines based on this basic structure, each with all the details for each object/table hard-coded?

     



  • @Mason Wheeler said:

    Object is whatever object you're trying to populate.  Property is whatever property you're trying to populate.

    Yeah.  "Property," singular.  That's where the example breaks down. If I had a method called "GetAccounts," for example, that queried the database, it would almost certainly return a data set consisting of several different columns. (Name: string; Address: string; Balance: currency, etc...)  This requires multiple distinct properties on the Account objects in order to represent the data.  How are you mapping multiple columns to multiple properties?

    instance.Property1 = row["property1"];

    instance.Property2 = row["property2"];

    instance.Property3 = row["property3"];

    etc...

    Why do you have more than one type of data in a single table?  Why not return multiple tables?

    Sorry, I guess it wasn't clear what I'm asking. What I meant was, how do you get this code to correctly process individual queries to more than one different table, at different times?  Or do you have multiple different routines based on this basic structure, each with all the details for each object/table hard-coded?

    Generally we have multiple routines.  We also have some places where the object is not defined specifically, where we just if the column exists.  But if I was going to do more dynamically created queries, I would just use LINQ.


  • @Sutherlands said:

    and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)
    Hardly game-breaking even if it were true, and the different versions do different things... one short-circuits and one doesn't.  How are those two not needed?

    I don't think I've ever needed, or even seen an example of, code that requires that the evaluation of a boolean expression *not* short-circuit in order to run correctly.  If you have code like that... I really can't imagine what you're doing but you're almost certainly doing something very very wrong.  So I see no point in having a non-short-circuiting operator.

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.
    Example?

    The runtime, for one.  Managed code, everything-as-objects, etc.

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.
    How is a string in C# more complicated than it needs to be?

    One, it's an object.  Two, it's immutable.  (Seriously, what idiot thought that was a good idea?) Three, an empty string != a null/unassigned string.  That's just asking for all kinds of trouble.  (Such as the example given here.)

    Also, that "bug" is "literally impossible" without having running as trusted code.  Which is why you don't run unknown dlls in full-trust.

    Nowhere in the example does it say that it must be executed from an external DLL...

     



  • @Mason Wheeler said:

    It's C-based syntax is difficult to read,

    C# is based on the reality that most programmers are already familiar with C-type syntax, be it from C itself, C++, Java, or JavaScript. Microsoft is a quintessentially pragmatic engineering company.

    @Mason Wheeler said:

    (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)

    I could see that, but... that counts as "a lot of baggage?" Seems pretty trivial to me.

    @Mason Wheeler said:

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.

    Sure you can. Or you could just not use the framework at all and roll your own. Hell, you could roll your own CLR compiler if you wanted.

    @Mason Wheeler said:

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.

    Gee, it's almost as if that code was "getting beneath" the String abstraction...

    @Mason Wheeler said:

    That is the link. How can you miss it?

    There are great programs written in C. There are shitty programs written in C# and Delphi. How is that possible?

    @Mason Wheeler said:

    Irrelevant, unless you can show me a language that makes it difficult to produce bad programs.

    You seem to have missed my point. A powerful language makes it easier to write programs. Period. Irrespective of quality. Do you deny that?

    Good programmers come from good development teams; those good development teams would produce a good program whether they were using FORTRAN '77 or .net 4.0, because that's pretty much what defines them as "good development teams".

    I would argue that the C#/.net/Visual Studio/WinForm combination makes it significantly harder to write a bad Windows GUI program than a good one. I'm sure you disagree, because of course you do I mentioned Microsoft products, but that's ok! It turns out we're allowed to have our own opinions. (I would also argue that some language make it nearly impossible to write good software, for example Perl and PHP.)

    The real problem with this debate is that you're so frustratingly close-minded, it's like nothing exists outside Delphi. Maybe concede a point, even a tiny point, just once? Maybe then we'd give a shit what you have to say? Until then it's just DELPHI DELPHI DELPHI BOW BEFORE DELPHI WORSHIP DELPHI ALSO SOME MICROSOFT SUX IN THERE! all the time.



  • @Mason Wheeler said:

    @Sutherlands said:

    and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)
    Hardly game-breaking even if it were true, and the different versions do different things... one short-circuits and one doesn't.  How are those two not needed?

    I don't think I've ever needed, or even seen an example of, code that requires that the evaluation of a boolean expression not short-circuit in order to run correctly.  If you have code like that... I really can't imagine what you're doing but you're almost certainly doing something very very wrong.  So I see no point in having a non-short-circuiting operator.

    Oh for fucks sake, the non short-circuiting operator is for bit twiddling.

    @Mason Wheeler said:

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.
    Example?

    The runtime, for one.  Managed code, everything-as-objects, etc.


    Explain what is wrong with the runtime,everything-as-objects and managed code.

    @Mason Wheeler said:

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.
    How is a string in C# more complicated than it needs to be?

    One, it's an object.  Two, it's immutable.  (Seriously, what idiot thought that was a good idea?) Three, an empty string != a null/unassigned string.  That's just asking for all kinds of trouble.  (Such as the example given here.)


    1 Why should it matter 2. From my C++ background I agree here. 3. I can see the logic behind having an empty string being different than a null string.



  • @delta534 said:

    Oh for fucks sake, the non short-circuiting operator is for bit twiddling.

    If Wheeler and I are on the same page, the point he's making is that in 2011 we shouldn't be doing bit twiddling anymore. Or at least not enough to make it an operator in the language.

    @delta534 said:

    3. I can see the logic behind having an empty string being different than a null string.

    For one thing, it helps you interact with database systems that also differentiate between an empty string and null.



  • @Mason Wheeler said:

    @Sutherlands said:

    and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)
    Hardly game-breaking even if it were true, and the different versions do different things... one short-circuits and one doesn't.  How are those two not needed?

    I don't think I've ever needed, or even seen an example of, code that requires that the evaluation of a boolean expression *not* short-circuit in order to run correctly.  If you have code like that... I really can't imagine what you're doing but you're almost certainly doing something very very wrong.  So I see no point in having a non-short-circuiting operator.

    In most cases probably true.  That doesn't mean that having both is "baggage", or that it isn't useful.

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.
    Example?

    The runtime, for one.  Managed code, everything-as-objects, etc.

    Those aren't examples.  Those are just words.  What do you want to de-abstract that you can't?

    Remember that thing that was posted a few weeks ago on here about redefining string.Empty?  A bug like that is literally impossible without a runtime that defines strings as something way more complicated than they need to be.
    How is a string in C# more complicated than it needs to be?

    One, it's an object.  Two, it's immutable.  (Seriously, what idiot thought that was a good idea?) Three, an empty string != a null/unassigned string.  That's just asking for all kinds of trouble.  (Such as the example given here.)

    It's an object? As opposed to a struct?  How does that make it more complicated?  "How is an int complicated? It's a struct!"  Seriously, that's not an answer.  Immutable... what is your argument for mutable strings? (Seriously, what idiot thinks that's a good idea?)  empty string != null?  DUH!  You must be one of those idiots that uses Oracle.

    Also, that "bug" is "literally impossible" without having running as trusted code.  Which is why you don't run unknown dlls in full-trust.

    Nowhere in the example does it say that it must be executed from an external DLL...

    You're right, it doesn't.  But you can do a lot of stuff with reflection that you would never want to do.  Why would you purposefully break the string abstraction in your own code?


  • @Mason Wheeler said:

    Two, it's immutable.  (Seriously, what idiot thought that was a good idea?)



  • @blakeyrat said:

    @delta534 said:
    Oh for fucks sake, the non short-circuiting operator is for bit twiddling.
    If Wheeler and I are on the same page, the point he's making is that in 2011 we shouldn't be doing bit twiddling anymore. Or at least not enough to make it an operator in the language.
    He was saying you shouldn't need a non-short-circuit version.  Which would mean that & would be both bit-twiddling and the regular logical operator (short-circuiting).  Not much of an argument against using a language, but that's what it is...



  • @blakeyrat said:

    @Mason Wheeler said:
    Irrelevant, unless you can show me a language that makes it difficult to produce bad programs.

    You seem to have missed my point. A powerful language makes it easier to write programs. Period. Irrespective of quality. Do you deny that?

    Sure do. When I think of "easy to write programs, period, irrespective of quality," one language stands out, far above all others, in my mind: Visual Basic.  (Not VB.Net, classic VB.) And... well... just look at how many TDWTF entries we get that are written in VB.  It's a very something language, but "powerful" is not the word I would use to fill in that particular blank.

    Good programmers come from good development teams;

    ...huh?  Then where do the teams get their programmers from?

    The real problem with this debate is that you're so frustratingly close-minded, it's like nothing exists outside Delphi. Maybe concede a point, even a tiny point, just once?

    Seriously?  You haven't noticed that when people make valid points, I agree with them?

    If I may make a counter-observation, you seem to be so focused on me being wrong in my opinions that that's the only thing you notice. Serious case of confirmation bias here...

     



  • @Mason Wheeler said:

    Seriously?  You haven't noticed that when people make valid points, I agree with them?

    I looked back over the last page and saw 1 instance of you just agreeing with what someone said.  I saw more instances of you claiming that what someone said simply didn't make sense in English.


  • @Mason Wheeler said:

    Sure do. When I think of "easy to write programs, period, irrespective of quality," one language stands out, far above all others, in my mind: Visual Basic. (Not VB.Net, classic VB.) And... well... just look at how many TDWTF entries we get that are written in VB. It's a very something language, but "powerful" is not the word I would use to fill in that particular blank.

    Are we getting that number of entries because VB is a bad language, or because it's a popular language?

    Did VB6 "classic" have issues? Of course. It had lots of issues. It makes me wonder if the people who gripe about the .net framework remember how shitty VB's various dependencies were. But it wasn't a bad language, and it definitely had the right idea when it comes to what's important in a language.

    @Mason Wheeler said:

    Good programmers come from good development teams;

    ...huh?  Then where do the teams get their programmers from?

    Monster.com? I don't understand what you're trying to imply here...

    Programmers are generally one of the least important factor in a good programming team, from my experience.

    @Mason Wheeler said:

    Seriously? You haven't noticed that when people make valid points, I agree with them?

    Nope.

    @Mason Wheeler said:

    If I may make a counter-observation, you seem to be so focused on me being wrong in my opinions that that's the only thing you notice. Serious case of confirmation bias here...

    You hadn't noticed that when you made a valid point a few posts up, I agreed with you?

    The difference between me and you is you wrote a paragraph describing what a good programming language looks like, but then kept ranting against C# even though C# met all of the requirements you laid out for a good programming language! It's really the hypocrisy that bugs me.

    Also I'm trolling you.



  • @Mason Wheeler said:

    Also I'm trolling you.

    blakey: FTFY


  • @Sutherlands said:

    @Mason Wheeler said:

    Also I'm trolling you.

    blakey: FTFY

    OH SNAP!



  • @delta534 said:

    @Mason Wheeler said:

    @Sutherlands said:

    and it carries a lot of baggage from C even though it's fixed the real problems behind them, (there is no good reason why any modern language should still need two different versions of the and and or operators, for example,)

    Hardly game-breaking even if it were true, and the different versions do different things... one short-circuits and one doesn't.  How are those two not needed?

    I don't think I've ever needed, or even seen an example of, code that requires that the evaluation of a boolean expression *not* short-circuit in order to run correctly.  If you have code like that... I really can't imagine what you're doing but you're almost certainly doing something very very wrong.  So I see no point in having a non-short-circuiting operator.

    Oh for fucks sake, the non short-circuiting operator is for bit twiddling.

    Oh, so then what you meant is "bitwise," not "non short-circuiting"?  Short-circuiting is for boolean evaluation; the term is meaningless when you're doing bitwise operations on non-boolean values, such as numbers.

    But that brings me back to the origina point.  C needed two different operators because it has no boolean type (everything is a boolean, including a number) and therefore the compiler can't make the distinction between a boolean operation and a bitwise operation, so you have to do it for the compiler.  C# has a boolean type, so there's no reason you should still be required to do the compiler's work for it. There should be one and operator and one or operator.  It should translate that to a boolean operation when it sees two boolean operands, a bitwise operation when it sees two numeric operands, and a syntax error when it sees something nonsensical like one boolean and one numeric operand.

    @Mason Wheeler said:

    and the .NET framework it's based upon creates several baseline abstractions that you can't get beneath.
    Example?

    The runtime, for one.  Managed code, everything-as-objects, etc.


    Explain what is wrong with the runtime, everything-as-objects and managed code.

    Oh, for heaven's sake! Why is it that everyone here needs every little detail spelled out?!? Has anyone here besides me ever worked on a large, complicated piece of software? This is getting ridiculous...

    @Mason Wheeler said:

    One, it's an object.  Two, it's immutable.  (Seriously, what idiot thought that was a good idea?) Three, an empty string != a null/unassigned string.  That's just asking for all kinds of trouble.  (Such as the example given here.)


    1 Why should it matter 2. From my C++ background I agree here. 3. I can see the logic behind having an empty string being different than a null string.

    1) Because there's no need for a string to be an object. Making it one simply for the sake of making everything an object overcomplicates the design of the language and everything based on it.  (See my earlier remark about basic engineering.)

    3) Really? Because I honestly can't.  Someone mentioned that some databases can have an empty, non-null string, and yes, I'm sure they can.  But that doesn't provide any good reason to actually make that distinction.  Just because something can be done doesn't mean that it should, or that it makes any sense when you do do it.

     



  • @Mason Wheeler said:

    Oh, so then what you meant is "bitwise," not "non short-circuiting"? 
    No, he didn't, because I said that, not him, and I meant exactly what I said.

    Oh, for heaven's sake! Why is it that everyone here needs every little detail spelled out?!? Has anyone here besides me ever worked on a large, complicated piece of software? This is getting ridiculous...

    Yes, because you still haven't answered.  Nobody here but you "knows" these mysterious things that you know, so we need you to tell us.  Except you just keep saying "the things, man!"

    1) Because there's no need for a string to be an object. Making it one simply for the sake of making everything an object overcomplicates the design of the language and everything based on it.  (See my earlier remark about basic engineering.)

    3) Really? Because I honestly can't.  Someone mentioned that some databases can have an empty, non-null string, and yes, I'm sure they can.  But that doesn't provide any good reason to actually make that distinction.  Just because something can be done doesn't mean that it should, or that it makes any sense when you do do it.

    1) I have not encountered a single design that was more complicated because string inherits from object.  Once again, the burden is on you to provide an example.

    3) What should this code return?

    class SampleClass { public string SampleProperty { get; set; } };

    bool SomeFunction() { return new SampleClass() == null; }

    I think most reasonable people would say false.  If that is false, why would replacing that with "return new String() == null;" be any different?  You still haven't provided any reason why they SHOULD be that way.



  • @Mason Wheeler said:

    Explain what is wrong with the runtime, everything-as-objects and managed code.

    Oh, for heaven's sake! Why is it that everyone here needs every little detail spelled out?!? Has anyone here besides me ever worked on a large, complicated piece of software? This is getting ridiculous...

    Uh, you didn't answer the question there, buddy.

    @Mason Wheeler said:

    3) Really? Because I honestly can't.  Someone mentioned that some databases can have an empty, non-null string, and yes, I'm sure they can.  But that doesn't provide any good reason to actually make that distinction.  Just because something can be done doesn't mean that it should, or that it makes any sense when you do do it.

    There's an entire forum here dedicated to calling a database shit, primarily because it can't distinguish between "" and null. Maybe you should read some of the posts and enlighten yourself.

    There's also the whole "you can box any variable type and make it nullable in .net" thing.



  • @Sutherlands said:

    @Mason Wheeler said:

    Oh, so then what you meant is "bitwise," not "non short-circuiting"? 
    No, he didn't, because I said that, not him, and I meant exactly what I said.

    OK, my mistake.  Too many overlapping questions coming from too many people at once.   Sorry 'bout that.

    So what do you mean by short-circuiting vs. non short-circuiting, then?  Because as I pointed out, (non) short-circuiting is meaningless when applied to non-boolean operations, and I've never seen an example of where you would want a non short-circuiting boolean evaluation.

    Oh, for heaven's sake! Why is it that everyone here needs every little detail spelled out?!? Has anyone here besides me ever worked on a large, complicated piece of software? This is getting ridiculous...
    Yes, because you still haven't answered.  Nobody here but you "knows" these mysterious things that you know, so we need you to tell us.  Except you just keep saying "the things, man!"

    I'm sorry.  I'm usually quite good at communicating and explaining things, and I really don't understand why nothing I'm saying seems to be getting through here.  It's like there's some fundamental piece of experience that most of you don't have, and without it it's impossible to establish the necessary common ground required to exchange ideas effectively.  Most of these "mysterious things that I know" are fundamentals to me, things that are so obvious they don't really need to be explained.

    I sincerely apologize if that causes difficulty for the rest of you.  That's honestly not my intention.

    1) Because there's no need for a string to be an object. Making it one simply for the sake of making everything an object overcomplicates the design of the language and everything based on it.  (See my earlier remark about basic engineering.)

    3) Really? Because I honestly can't.  Someone mentioned that some databases can have an empty, non-null string, and yes, I'm sure they can.  But that doesn't provide any good reason to actually make that distinction.  Just because something can be done doesn't mean that it should, or that it makes any sense when you do do it.

    1) I have not encountered a single design that was more complicated because string inherits from object.  Once again, the burden is on you to provide an example.

    3) What should this code return?

    class SampleClass { public string SampleProperty { get; set; } };

    bool SomeFunction() { return new SampleClass() == null; }

    I think most reasonable people would say false.  If that is false, why would replacing that with "return new String() == null;" be any different?  You still haven't provided any reason why they SHOULD be that way.

     

    Your example for #3 is the perfect response to your question about #1.  You've created a new string that contains no information, which is therefore functionally indistinguishable from NULL (which means "no information"), and yet because it's an object and not something sensible like an array of chars, it can exist in a nonsensical state where it contains no information but is not NULL.  That will make all your string handling code more complicated than it needs to be.

     


Log in to reply