Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
HFX
Nov 29, 2004

TagUrIt posted:

code:
sb.append(String.format("%10d", suffix));
Edit: Okay, not a horror. Just an odd piece of code.

It could be a bug, but would be very likely in a pre 1.5 environment. I was unaware of the format on String until you mentioned it. Now, I feel terrible for some places where I used while loops on String buffers to pad them.

Flobbster posted:

Java should have C# envy, because C# shows how to do a Java-like language that isn't complete poo poo.

No, C# is what you get when you try to add features to attract every developer to your platform without designing for the features originally in mind. C# has turned into a mess of a language with some many features I am not even sure why they exist.

Adbot
ADBOT LOVES YOU

npe
Oct 15, 2004

HFX posted:

It could be a bug, but would be very likely in a pre 1.5 environment. I was unaware of the format on String until you mentioned it. Now, I feel terrible for some places where I used while loops on String buffers to pad them.

No, this guy is just crazy, this is all recent code (within the last year) and we regularly use StringUtils (which has a leftPad() function) all over the place. He also likes to pack multiple variables into a single comma separated string so it can later be picked apart via substring() to get at the relevant parts. This is to "work around" java's lack of multiple return values as he puts it.

HFX
Nov 29, 2004

npe posted:

No, this guy is just crazy, this is all recent code (within the last year) and we regularly use StringUtils (which has a leftPad() function) all over the place. He also likes to pack multiple variables into a single comma separated string so it can later be picked apart via substring() to get at the relevant parts. This is to "work around" java's lack of multiple return values as he puts it.

Couldn't he just use a list to do the same thing, thereby forming a tuple?

trex eaterofcadrs
Jun 17, 2005
My lack of understanding is only exceeded by my lack of concern.

HFX posted:

Couldn't he just use a list to do the same thing, thereby forming a tuple?

I always end up having a generic class called Pair for just this reason.
Usually something like this: http://www.ideograph.com/content/generic-pair-java

npe
Oct 15, 2004

HFX posted:

Couldn't he just use a list to do the same thing, thereby forming a tuple?

His response to all of these types of questions is "this works pretty well."

He's crazy. I just try to keep him away from anything I'll have to work on.

Crazy RRRussian
Mar 5, 2010

by Fistgrrl

npe posted:

His response to all of these types of questions is "this works pretty well."

He's crazy. I just try to keep him away from anything I'll have to work on.

It's pretty inefficient tho. If you had to do that a poo poo load of times it would probably slow down your program's performance by quite a bit versus using a list or your own Pair class or something.

shrughes
Oct 11, 2008

(call/cc call/cc)

HFX posted:

No, C# is what you get when you try to add features to attract every developer to your platform without designing for the features originally in mind. C# has turned into a mess of a language with some many features I am not even sure why they exist.

What features are these? I was going to assume that you're a moron, but first, I'd like to know how you are a moron.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

shrughes posted:

What features are these? I was going to assume that you're a moron, but first, I'd like to know how you are a moron.

Isn't it obvious? Mutable references, looping constructs, and non-Church-encoded data structures. They're clearly just pandering to the hardcore iterative assembly programmers, without any thought given to the added complexity forced upon your average, everyday pure functional programmer.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Crazy RRRussian posted:

It's pretty inefficient tho. If you had to do that a poo poo load of times it would probably slow down your program's performance by quite a bit versus using a list or your own Pair class or something.

If you were using a language with serious string capabilities like MUMPS your packed strings would be efficient :smug:

Crazy RRRussian
Mar 5, 2010

by Fistgrrl

Zhentar posted:

If you were using a language with serious string capabilities like MUMPS your packed strings would be efficient :smug:

What the gently caress is MUMPS? Isn't that a nasty disease that kills kids?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
MUMPS is a bad language used by a bad company that Zhentar has Stackholm Syndrome about so that he won't commit suicide. (I worked there too but then I realized that that was a shameful thing to do.)

Hoborg
Oct 19, 2006

by T. Mascis

Crazy RRRussian posted:

What the gently caress is MUMPS? Isn't that a nasty disease that kills kids?

It's also a nasty programming language that has quite a reputation.

I wouldn't be surprised if some programmer made a mistake in it that indirectly lead to the deaths of several children seeming as it doesn't even do arithmetic normally (strict left-to-right evaluation, no operator precedence).

EDIT: Argh, beaten to it by a dentist.

Hoborg
Oct 19, 2006

by T. Mascis

shrughes posted:

What features are these? I was going to assume that you're a moron, but first, I'd like to know how you are a moron.

My perception is a lot of developers think the addition of things like Linq, Lambda expressions, and the new classes added in later framework revisions amount to bloat.

Of course, the good thing is that these features are implemented using context-sensitive keywords, so you can continue to call some variable "select" and not have it conflict with the select Linq keyword.

I personally feel C# is getting bloated. I've only ever used Linq when doing data-access (using Linq-to-SQL because I was feeling lazy). I hope they devise a formal way to modularise the language so we can add our own language extensions in a portable and compatible manner. I'd love to introduce some new keywords and constructs to take the pain out of writing ORMs.

Zhentar
Sep 28, 2003

Brilliant Master Genius

Hoborg posted:

I wouldn't be surprised if some programmer made a mistake in it that indirectly lead to the deaths of several children seeming as it doesn't even do arithmetic normally (strict left-to-right evaluation, no operator precedence).

I wouldn't know about that, but I have recently seen a section in a financial report off by a few hundred billion dollars thanks to an order of operations related bug.

HFX
Nov 29, 2004

shrughes posted:

What features are these? I was going to assume that you're a moron, but first, I'd like to know how you are a moron.

Partial classes (This one in particular.. give me a good reason for it)
Support for only unchecked exceptions. (Random crashing ahoy. Almost as bad as Java Programmers who have empty catches.)
LINQ's (Now you are mixing languages. Makes your life easier, but I don't think it should be a first class feature)
The use of virtual keyword to allow polymorphism. (Why not just do virtual by default? For the type of language C# is, it would have made more sense).
Structs (Why? You have classes. This is for C/C++ programmers)
Dynamic Typing (Doesn't this break the original idea of C#? See below for why it can be good)

The rest of my complaints is the C# does not straight jacket the programmer enough. I've learned if you give most programmers the ability too, they will optimize way to early and use every construct they can to make their life easier but not necessarily a better running or maintainable program. I prefer a smaller core language with libraries to handle many special features. Even better is being able to create DSL's inside of the language.

However, I many of the features which have found their way into C# can be used to define other languages so they run in the CLI. I'm just not sure they should have been crammed into C#.

Hoborg posted:

My perception is a lot of developers think the addition of things like Linq, Lambda expressions, and the new classes added in later framework revisions amount to bloat.

Of course, the good thing is that these features are implemented using context-sensitive keywords, so you can continue to call some variable "select" and not have it conflict with the select Linq keyword.

I personally feel C# is getting bloated. I've only ever used Linq when doing data-access (using Linq-to-SQL because I was feeling lazy). I hope they devise a formal way to modularise the language so we can add our own language extensions in a portable and compatible manner. I'd love to introduce some new keywords and constructs to take the pain out of writing ORMs.

Hoborg pretty much states my feelings.



Edit: I'd really like a language that makes things as simple as possible to begin with. If needed for performance or algorithmic reasons, I could then use more advanced / dangerous concepts. I sort of found this with OCaml and Haskell.

HFX fucked around with this message at 22:10 on Jun 1, 2010

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog
In before shrughes calls you a moron.
My only comment: it's pretty trivial to imagine a scenario where partial classes are useful. Any generated code that could be extended by hand-written code can be trivially combined via partial classes with no chance of your work being clobbered by a regeneration.

HFX
Nov 29, 2004

Smugdog Millionaire posted:

In before shrughes calls you a moron.
My only comment: it's pretty trivial to imagine a scenario where partial classes are useful. Any generated code that could be extended by hand-written code can be trivially combined via partial classes with no chance of your work being clobbered by a regeneration.

I can find them useful at times. That doesn't mean I feel they are great for a language. I also criticize many languages so it isn't like I single out C#. If he wants to call me a moron then I can call him a jackass.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

HFX posted:

Partial classes (This one in particular.. give me a good reason for it)
Generated code where you want the user to be able to add to the class, but also want to be able to re-generate the generated part without destroying changes.

quote:

Support for only unchecked exceptions. (Random crashing ahoy. Almost as bad as Java Programmers who have empty catches.)
I don't even know what the hell you mean here. How do unchecked exceptions cause "random crashing"? Mandatory checked exceptions are terrible.

quote:

LINQ's (Now you are mixing languages. Makes your life easier, but I don't think it should be a first class feature)
Not sure how I'm mixing languages when I use LINQ to query IEnumerables. It's not LINSQL.

quote:

The use of virtual keyword to allow polymorphism. (Why not just do virtual by default? For the type of language C# is, it would have made more sense).
You might as well ask "why is there a sealed keyword?" - explicitly declaring what methods have different behavior if you have an instance of Derived instead of Base is important.

quote:

Structs (Why? You have classes. This is for C/C++ programmers)
A struct is a value type. It's fundamentally different from a class.

quote:

Dynamic Typing (Doesn't this break the original idea of C#? See below for why it can be good)
Dynamic types in C# exist pretty much exclusively to provide a way to handle other actual dynamic languages running in the CLR.


I'm not going to go so far as to call you an idiot, but you're pretty much entirely wrong. This really belongs in "Things you love/hate..." though.

HFX
Nov 29, 2004

Ryouga Inverse posted:

Generated code where you want the user to be able to add to the class, but also want to be able to re-generate the generated part without destroying changes.

I don't even know what the hell you mean here. How do unchecked exceptions cause "random crashing"? Mandatory checked exceptions are terrible.

Not sure how I'm mixing languages when I use LINQ to query IEnumerables. It's not LINSQL.

You might as well ask "why is there a sealed keyword?" - explicitly declaring what methods have different behavior if you have an instance of Derived instead of Base is important.

A struct is a value type. It's fundamentally different from a class.

Dynamic types in C# exist pretty much exclusively to provide a way to handle other actual dynamic languages running in the CLR.


I'm not going to go so far as to call you an idiot, but you're pretty much entirely wrong. This really belongs in "Things you love/hate..." though.

I think I can agree to the things you love / hate.

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog
Structs are real handy for p/invoke.

lumberjack4
May 14, 2010

Structs are a hell of a lot better than classes performance wise. Why go through all the overhead of creating a class when a simple struct will suffice?

Hoborg
Oct 19, 2006

by T. Mascis

lumberjack4 posted:

Structs are a hell of a lot better than classes performance wise. Why go through all the overhead of creating a class when a simple struct will suffice?

Depends on context. It would be misguided of a developer to swap all occurences of 'class' with 'struct' in code.

Most of the only cases you'd see a performance benefit are examples of micro-optimizations, something Knuth speaks out against. You should focus on ensuring your program is correct, not that you're preventing a few bytes on the heap from being fragmented by putting structs on the stack instead.

Destroyenator
Dec 27, 2004

Don't ask me lady, I live in beer

HFX posted:

Partial classes (This one in particular.. give me a good reason for it)
Also used for ASP.net pages with C# backing files so the controls defined in ASP and the members and methods defined in the C# can be used together.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Hoborg posted:

micro-optimizations, something Knuth speaks out against

Urge to sperg... rising...

lumberjack4
May 14, 2010

Hoborg posted:

Depends on context. It would be misguided of a developer to swap all occurences of 'class' with 'struct' in code.

Most of the only cases you'd see a performance benefit are examples of micro-optimizations, something Knuth speaks out against. You should focus on ensuring your program is correct, not that you're preventing a few bytes on the heap from being fragmented by putting structs on the stack instead.

When I'm creating millions of objects that only have 4 or 5 fields, a struct is light years ahead of going through the class creation overhead. I only tell people to replace classes with structs if the object is crazy simple. If you have an object with any complexity whatsoever, you'd almost never want to go the struct route. But to say that structs shouldn't be a part of the language is ludicrous.

Internet Janitor
May 17, 2008

"That isn't the appropriate trash receptacle."
Performance aside, structs are useful/necessary because C# is expected to interoperate with horrific legacy Windows APIs.

npe
Oct 15, 2004
Structs are nice for their non-nullability as well, which helps with ensuring correctness (or at least pushing the incorrect code around to where it should be).

shrughes
Oct 11, 2008

(call/cc call/cc)

HFX posted:

Partial classes (This one in particular.. give me a good reason for it)

First, I'd like to say, thank you for informing me of the ways that you are a moron. Since your estimates of reality are not completely identical to mine, I'm afraid that you're a moron.

Also, as has been said, partial classes are useful when you want to generate some code and then gently caress with it.

HFX posted:

Support for only unchecked exceptions. (Random crashing ahoy. Almost as bad as Java Programmers who have empty catches.)

This is one area in which I agree with you, not with regard to your spergtification about random crashing (which is dumb because Java has its whole RuntimeException hierarchy, ergo you are a moron), but rather, to add that I don't like Java's implementation in which you have to declare your exceptions on every method (instead of having the exception checking types inferred, which seems like it would be pretty easy). It would be better if you only had to declare it on certain methods, and for those it was checked, and for the rest it was just inferred.

HFX posted:

LINQ's (Now you are mixing languages. Makes your life easier, but I don't think it should be a first class feature)

All I can say is, yawn. Everybody just uses the extension methods anyway, nobody uses the weirder LINQ syntax except in the cases where it makes things clearer, like when doing joins. It really does make expressing joins easier, and so it's a feature that has helped making code more readable. I'm talking about the use of LINQ libraries and expressions for the purpose of operating over ordinary collections.

HFX posted:

The use of virtual keyword to allow polymorphism. (Why not just do virtual by default? For the type of language C# is, it would have made more sense).

The pattern of design in which methods are haphazardly overridden is a bad one. You are a moron. Explicitly declaring which methods are virtual forces people to actually say what can be overridden and thus makes it easier to reason about the behavior of an instance of a base class.

HFX posted:

Structs (Why? You have classes. This is for C/C++ programmers)

You think having reference types for everything is better or the primitive type haphazardry of Java is better? Then you are a moron.

Arrays of structs are more memory efficient and cache efficient than arrays of references, and sometimes you just need a struct.

Interestingly enough, the struct type and reference type dichotomy is a fairly natural result if you tell somebody to design a garbage collected, memory safe language with only value types with no RAII where fields are generally mutable. What you get is some kind of primitive "pointer" type being included in the language, and a "reference type" design pattern naturally emerges, in which certain value types' implementations involve containing only a ptr<Something>, where Something is a mutable object. Purely functional, nonlazy, immutable objects, on the other hand, don't need to be reference types (you can safely make shallow copies of immutable values for any level of shallowness). Or they can be partly reference, partly not -- maybe a reference to some mutable stuff with some locally stored mutable information, for example. So you could just as easily say that C#'s real problem is that it has reference types, not that it has value types.

HFX posted:

Dynamic Typing (Doesn't this break the original idea of C#? See below for why it can be good)

What original idea? I thought C# 2 was approximately the original idea. Doesn't C# 3 break that?

HFX posted:

The rest of my complaints is the C# does not straight jacket the programmer enough. I've learned if you give most programmers the ability too, they will optimize way to early and use every construct they can to make their life easier but not necessarily a better running or maintainable program. I prefer a smaller core language with libraries to handle many special features. Even better is being able to create DSL's inside of the language.

You complain about the lack of straight jacketing, yet you want to have every method be virtual. (Ergo, you are a moron. What are you going to do, call me a jackass? The best revenge is coding well.) C# does a fine job of directing the programmer towards good design. IDisposable and using blocks direct the programmer towards managing resources properly, instead of the hell that is Java. The fact that IEnumerable<T> : IDisposable, with the way generator functions work, does too. Writing a complicated IEnumerable, that acquires resources and releases them safely, is trivially easy to do in C#. I bet people get that wrong all the time in Java, or they just don't try. In C#, you can just put a yield statement inside a using block inside a foreach block, while wearing dark sunglasses at night just to look cool.

C#'s LINQ features encourage programmers to avoid manually writing and rewriting loop-based wizardry over and over again. And so instead of doing some loop that happens to filter elements while keeping some counter and other odd things, programmers can just say what they are doing. When it comes to increasing the probability of correct code, LINQ is worth it. Its main downside is that you have to learn a bunch of new words like Select, Where, Skip, GroupBy, and such, instead of manually implementing loopy constructs yourself, over and over again. The cost of having to know what Where means is less than the cost of incorrect code. Also, LINQ makes it more difficult to gently caress things up by having strange side effects in strange places, without feeling bad about the code you've written.

Also, almost every single feature since the initial release has given programmers more ways to straightjacket themselves, with more ways to talk about the types they are using and the things that they are doing, instead of saying "I give up, just cast," or "I give up, just modify this variable," or "I give up, return an object[] with two elements." The biggest contributor to good software design in C# has been clean lambda expressions, and second after that is generics. As far as I can see, there isn't any bloat, there's just stuff that's there. LINQ expressions are there, but I can ignore that option, but sometimes they're useful. You know, to most sane people, list comprehensions are considered a normal language feature, if not an essential one, and that's all LINQ expressions really are.

HFX posted:

Edit: I'd really like a language that makes things as simple as possible to begin with. If needed for performance or algorithmic reasons, I could then use more advanced / dangerous concepts. I sort of found this with OCaml and Haskell.

Haskell and OCaml are more complicated than C#, and when it comes to reasoning about the performance of your code, Haskell is borderline dangerous. I don't know OCaml, are you still limited to 4 million element arrays? It's more complicated than F# is, I know that.

Do you complain about do notation in Haskell, the way you complain about LINQ? What with do notation, scoped type variables, list comprehensions, stand-alone deriving declarations, postfix operators, view patterns, pattern guards, data families, n+k patterns, recursive do notation, generalized list comprehensions, record puns, rank n types, local fixity declarations, existentially quantified data constructors, GADTs, functional dependencies, overlapping/undecidable/incoherent instances, arrow notation, bang patterns, and a reliance on compiler optimizations that change big-O properties of the code, you mentioned Haskell after criticizing C# for getting too much bloat. You are a moron.

csammis
Aug 26, 2003

Mental Institution
Goddamn shrughes :golfclap:

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog
Boom. Headshot.

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy

shrughes posted:

and a reliance on compiler optimizations that change big-O properties of the code

Wait, what?!

Crazy RRRussian
Mar 5, 2010

by Fistgrrl
shrughes, chill out man, everything will be ok! All your custom gcj language needs is love, sweet love.

On serious note C# does sound pretty cool. I should probably look into it as java replacement. Can somebody comment on the state/quality of mono nowadays? Also does C# have something similar to java webstart?

HFX
Nov 29, 2004

shrughes posted:

First, I'd like to say, thank you for informing me of the ways that you are a moron. Since your estimates of reality are not completely identical to mine, I'm afraid that you're a moron.

Also, as has been said, partial classes are useful when you want to generate some code and then gently caress with it.

I can give you this. However, generated code is often a bane to long term maintainability. This problem can also be handled through several other methods without causing the issue of a class to be declared over several files.


shrughes posted:

This is one area in which I agree with you, not with regard to your spergtification about random crashing (which is dumb because Java has its whole RuntimeException hierarchy, ergo you are a moron), but rather, to add that I don't like Java's implementation in which you have to declare your exceptions on every method (instead of having the exception checking types inferred, which seems like it would be pretty easy). It would be better if you only had to declare it on certain methods, and for those it was checked, and for the rest it was just inferred.

I complain about Java's Runtime exceptions also. I have dealt several times with code where someone catches a Runtime exception and silently discards it. I've also had code where perfectly valid exceptions have decided to be wrapped inside of a runtime exception and then thrown. I do like having a reasonable expectation of what might be thrown from the method signature. I also have an IDE which takes the headache of figuring out what types of exceptions can be thrown.

shrughes posted:

All I can say is, yawn. Everybody just uses the extension methods anyway, nobody uses the weirder LINQ syntax except in the cases where it makes things clearer, like when doing joins. It really does make expressing joins easier, and so it's a feature that has helped making code more readable. I'm talking about the use of LINQ libraries and expressions for the purpose of operating over ordinary collections.

Why is this a first class feature of the language and not a library?

shrughes posted:

The pattern of design in which methods are haphazardly overridden is a bad one. You are a moron. Explicitly declaring which methods are virtual forces people to actually say what can be overridden and thus makes it easier to reason about the behavior of an instance of a base class.

This is great until you are working with several companies where you don't have source code to the upper class and you realize you need to override just one behavior. Implicit virtual is also simpler.

shrughes posted:

You think having reference types for everything is better or the primitive type haphazardry of Java is better? Then you are a moron.

Nope. Java is lovely here too and auto boxing was dumb. Everything should have been a object level with allowing a compiler / runtime to optimize primitives or specifically declaring a primitive type..

shrughes posted:

Arrays of structs are more memory efficient and cache efficient than arrays of references, and sometimes you just need a struct.

Premature optimizations for bad compilers / interpreters.

shrughes posted:

Interestingly enough, the struct type and reference type dichotomy is a fairly natural result if you tell somebody to design a garbage collected, memory safe language with only value types with no RAII where fields are generally mutable. What you get is some kind of primitive "pointer" type being included in the language, and a "reference type" design pattern naturally emerges, in which certain value types' implementations involve containing only a ptr<Something>, where Something is a mutable object. Purely functional, nonlazy, immutable objects, on the other hand, don't need to be reference types (you can safely make shallow copies of immutable values for any level of shallowness). Or they can be partly reference, partly not -- maybe a reference to some mutable stuff with some locally stored mutable information, for example. So you could just as easily say that C#'s real problem is that it has reference types, not that it has value types.

C# is a case where it you have both a value and reference world and it occasionally stinks.

shrughes posted:

What original idea? I thought C# 2 was approximately the original idea. Doesn't C# 3 break that?

C# 3 was when feature creep started to become apparent to me. For the most part I applauded C# up to 2.x as it was fixing 90% of my complaints with Java. I was willing to forgive some things they did add that I consider syntactic sugar.

I find myself using these features all the time. Doesn't mean I think they should have been added to the language.


shrughes posted:

You complain about the lack of straight jacketing, yet you want to have every method be virtual. (Ergo, you are a moron. What are you going to do, call me a jackass? The best revenge is coding well.) C# does a fine job of directing the programmer towards good design. IDisposable and using blocks direct the programmer towards managing resources properly, instead of the hell that is Java. The fact that IEnumerable<T> : IDisposable, with the way generator functions work, does too. Writing a complicated IEnumerable, that acquires resources and releases them safely, is trivially easy to do in C#. I bet people get that wrong all the time in Java, or they just don't try. In C#, you can just put a yield statement inside a using block inside a foreach block, while wearing dark sunglasses at night just to look cool.

I can agree with the IDisposable and Java's failure in this regard.

shrughes posted:

C#'s LINQ features encourage programmers to avoid manually writing and rewriting loop-based wizardry over and over again. And so instead of doing some loop that happens to filter elements while keeping some counter and other odd things, programmers can just say what they are doing. When it comes to increasing the probability of correct code, LINQ is worth it. Its main downside is that you have to learn a bunch of new words like Select, Where, Skip, GroupBy, and such, instead of manually implementing loopy constructs yourself, over and over again. The cost of having to know what Where means is less than the cost of incorrect code. Also, LINQ makes it more difficult to gently caress things up by having strange side effects in strange places, without feeling bad about the code you've written.

Still should have been in a library.

shrughes posted:

Also, almost every single feature since the initial release has given programmers more ways to straightjacket themselves, with more ways to talk about the types they are using and the things that they are doing, instead of saying "I give up, just cast," or "I give up, just modify this variable," or "I give up, return an object[] with two elements." The biggest contributor to good software design in C# has been clean lambda expressions, and second after that is generics. As far as I can see, there isn't any bloat, there's just stuff that's there. LINQ expressions are there, but I can ignore that option, but sometimes they're useful. You know, to most sane people, list comprehensions are considered a normal language feature, if not an essential one, and that's all LINQ expressions really are.

There are two worlds here and it depends on what I'm doing.

90% of the time: Shouldn't have to ask for the straight jacket. It is better to have the straight jacket and then ask to remove parts of it. Furthermore, LINQ sounds a lot like you want list to become the basic type of the language which is usually reserved for functional languages. C# did not start off that way and is not of that class in most ways.

10% of the time: Do what you think I mean.

shrughes posted:

Haskell and OCaml are more complicated than C#, and when it comes to reasoning about the performance of your code, Haskell is borderline dangerous. I don't know OCaml, are you still limited to 4 million element arrays? It's more complicated than F# is, I know that.

OCaml is still limited as I know for the arrays. I don't know how much it has been upgraded for 64 bit. It is why I moved onto Haskell. Neither are really more complicated then C#, and I dare say they are simpler once you wrap your mind around them.

shrughes posted:

Do you complain about do notation in Haskell, the way you complain about LINQ? What with do notation, scoped type variables, list comprehensions, stand-alone deriving declarations, postfix operators, view patterns, pattern guards, data families, n+k patterns, recursive do notation, generalized list comprehensions, record puns, rank n types, local fixity declarations, existentially quantified data constructors, GADTs, functional dependencies, overlapping/undecidable/incoherent instances, arrow notation, bang patterns, and a reliance on compiler optimizations that change big-O properties of the code, you mentioned Haskell after criticizing C# for getting too much bloat.

I do not complain about the notation of Haskell because of what Haskell is. I'm actually very comfortable with languages that don't use C like syntax. The language was designed from the ground up for the features. Some of its decisions were boneheaded and it does suffer from bloat at times.

shrughes posted:

You are a moron.

Then I will be a moron.

Crazy RRRussian posted:

shrughes, chill out man, everything will be ok! All your custom gcj language needs is love, sweet love.

On serious note C# does sound pretty cool. I should probably look into it as java replacement. Can somebody comment on the state/quality of mono nowadays? Also does C# have something similar to java webstart?

Mono is excellent although you will miss out on Winforms. Performance is not as good as Microsoft's CLI implementation. You can always download a VS Express if you want to play with any .Net language. Keep your eye out for MSDN offers which allow you to get lots of nice stuff for a low price.

As a Java replacement, I am not so sure. There are a lot of libraries that have been implemented, but don't expect everything you need to do to be replaceable. In particular, I've haven't found a library that plays nicely with Sun RPC.

HFX fucked around with this message at 04:54 on Jun 2, 2010

shrughes
Oct 11, 2008

(call/cc call/cc)

niteice posted:

Wait, what?!

Strictness optimizations change memory usage.

For example, without magic optimization, evaluation of sum [1..n] looks something like this. I use "{n-1}" or "{expr}" to represent the strictly-evaluated number n-1, rather than an unevaluated expression that would subtract 1 from n when evaluated.
code:
sum [1..n]   => foldl (+) 0 [1..n]
             => foldl (+) (0 + 1) [2..n]
             => foldl (+) ((0 + 1) + 2) [3..n]
             => ...
             => foldl (+) (((...((0 + 1) + 2) + ...)) + (n-1)) [n]
             => foldl (+) ((((...((0 + 1) + 2) + ...)) + (n-1)) + n) []
             => ((((...((0 + 1) + 2) + ...)) + {n-1}) + n)
             => ((((...(1       + 2) + ...)) + {n-1}) + n)
             => ((((... 3            + ...)) + {n-1}) + n)
             => ...
             => {n*(n-1)/2} + n
             => {n*(n+1)/2}
Note that this builds up an unevaluated expression whose length is proportional to n. When evaluating the unevaluated expression, you, depending on the implementation, might get n levels of recursion, resulting in a stack overflow when summing long lists.

And here's what the behavior looks like after optimization.
code:
sum [1..n] => foldl' (+) 0 [1..n]
           => foldl' (+) 1 [2..n]
           => foldl' (+) 2 [3..n]
           => ...
           => foldl' (+) {n*(n-1)/2} [n]
           => foldl' (+) {n*(n+1)/2} []
           => {n*(n+1)/2}
Now the memory usage is O(1) instead of O(n). (Or it's O(log n) instead of O(n log n), if you're using arbitrary precision integers and want to be technical.)

Generally speaking, memory leaks like this just happen, and Haskell is a broken language because of this problem. I refer you to this post where the Snap framework failed a benchmark due to a memory leak: http://news.ycombinator.com/item?id=1380732



Crazy RRRussian posted:

On serious note C# does sound pretty cool. I should probably look into it as java replacement. Can somebody comment on the state/quality of mono nowadays? Also does C# have something similar to java webstart?

I think Clojure or Scala make for better Java replacements, if all you want is a better programming language, especially if you're mentioning Mono.

shrughes
Oct 11, 2008

(call/cc call/cc)

HFX posted:

:words:

Classes being declared over several files is not an issue.
On LINQ: adding macros and implementing it out of that, adding C++-style template expansion with whitespace operators, or adding list comprehension syntax: which is the least bloaty choice?
LINQ is already a library. I made it clear where I was referring to LINQ expressions versus System.Linq, the library.
Overriding some random method of a parent class requires verifying that nothing in the base class uses the method, and dissembling code is worse than generating it.
To imply that simpler implies better implies that you are a moron.
Stop invoking the sufficiently smart compiler fallacy.
If you dislike value types then you dislike semantically equivalent non-nullable immutable reference types which means you are a moron. Either that or you invoked the sufficiently smart compiler fallacy in the name of nullable references or non-nullable references to mutable objects. You are a moron.
Premature optimization is no worse than premature anti-optimization.
Your dislike of syntactic sugar is religious in nature, you are a moron.
I was talking about System.Linq, the library. You are a moron.
Your straightjacket metaphor could be taken to logical extremes and you have not articulated where it breaks down.
IEnumerable is not the same thing as list, and the one-time-through idiom encourages the use of arrays, not linked lists.
90% of the time you are a moron, 10% of the time you are lucky.
Unblitheringly used, Haskell is much more complicated than C#.
Your inference that C-like syntax was on the table betrays the smallness of your thoughts.
Haskell evolved. Monads and do notation were added later.
You will be and always have been a moron.

raminasi
Jan 25, 2005

a last drink with no ice

shrughes posted:

Strictness optimizations change memory usage.

So this is a consequence of Haskell's laziness, and doesn't afflict languages that don't try to do that? Or do languages with fold (and the like) generally not specify anything about their implementation? (I really want to understand this correctly.)

tef
May 30, 2004

-> some l-system crap ->

HFX posted:

This is great until you are working with several companies where you don't have source code to the upper class and you realize you need to override just one behavior. Implicit virtual is also simpler.

If by simpler, you mean 'Easier to write fragile code that breaks', sure.

HFX
Nov 29, 2004

GrumpyDoctor posted:

So this is a consequence of Haskell's laziness, and doesn't afflict languages that don't try to do that? Or do languages with fold (and the like) generally not specify anything about their implementation? (I really want to understand this correctly.)

The part he is trying to show why Haskell is flawed is its being lazy by default. It runs out of memory because he keeps pushing thunks until it reaches the end at which time it knows it has to compute everything. Unfortunately, it is very easy to exceed the available space while doing this.

HFX fucked around with this message at 14:26 on Jun 2, 2010

shrughes
Oct 11, 2008

(call/cc call/cc)

GrumpyDoctor posted:

So this is a consequence of Haskell's laziness, and doesn't afflict languages that don't try to do that? Or do languages with fold (and the like) generally not specify anything about their implementation? (I really want to understand this correctly.)

The problem I mentioned doesn't afflict strictly evaluated languages at all.

In general, languages with fold and map and such specify varying amounts about their implementation. Haskell specifies the implementation very restrictively -- you'll get the same value from the same expression on any correct interpreter or compiler. It doesn't really specify how you must go about getting that value, though, but you will always get the right value. Some other languages are defined more loosely. For example, R5RS Scheme doesn't specify whether map evaluates its values from left to right or right to left. It also doesn't specify the order in which function parameter expressions are evaluated either. And so (+ (display "foo") (display "bar")) can have different outcomes. I suspect that OCaml specifies evaluation order for functions like these more tightly.

Unless I'm mistaken, the semantics of Haskell dictate things in such a way that when you want the value of a certain expression then you're going to (under the semantics of lazy evaluation or call-by-name evaluation -- it does not matter) evaluate a certain set of other expressions, and no other expressions. For example, to evaluate const (:) x y z, you will not evaluate the expressions x, y, or z. You will, however, evaluate const (:) x, which involves evaluating const (:), I suppose. Then that's followed by (:) y z. But then you're done. Oh, maybe you evaluate const and (:) and even (:) y, if we want to get technical.

By the way, by "evaluating," I'm talking about evaluating something into weak head normal form.

Now, foldl' f w [x,y,z] is going to evaluate f w x, f (f w x) y, and f (f (f w x) y) z. Maybe these facts imply that expressions like w or z get evaluated. This depends on the function f and maybe on the other values.

On the other hand, foldl f w [x,y,z] is only guaranteed to evaluate f (f (f w x) y) z. If f were the sort of function that needs to evaluate its first argument, then we'd see the same expressions evaluated as we'd have seen evaluated under foldl. Whether f evaluates its first argument might depend on the value of the second argument. For example:

code:
Prelude Data.List> foldl (flip (||)) undefined [undefined, True]
True
Prelude Data.List> foldl (flip (||)) undefined [undefined, False]
*** Exception: Prelude.undefined
In the latter case, flip (||) needed to evaluate its first parameter because its second parameter was False. (flip (||) is just the operator (||) with its arguments reversed.) And so the expression (flip (||)) ((flip (||)) undefined undefined) False needed to evaluate ((flip (||)) undefined undefined), which in turn needed to evaluate its second parameter, which was undefined.

Some functions, like the instance of (+) that works on the Int type, will, when an expression like ((+) x y) is evaluated, always evaluate their first parameter, x. It's these functions f for which foldl f can be replaced with foldl' f, because we know the same set of expressions will end up being evaluated.

To see how fragile that sort of optimization can be, we could consider the expression foldl1 min xs. For primitive types like Int, we can expect evaluating (min x y) to cause the evaluation of both expressions x and y.

What if we have a type that adds a new minimum element to a given orderable type?

code:
data Foo a = NegativeInfinity | Foo a

instance Ord a => Ord (NInf a) where
    compare NegativeInfinity NegativeInfinity = EQ
    compare NegativeInfinity _                = LT
    compare _                NegativeInfinity = GT
    compare (Foo x)          (Foo y)          = compare x y

    min NegativeInfinity _                = NegativeInfinity
    min _                NegativeInfinity = NegativeInfinity
    min (Foo x)          (Foo y)          = Foo (min x y)
Well, that min is strict in its first argument. It is guaranteed to evaluate its first argument, because it needs match it against the pattern NegativeInfinity. And so foldl1 min for that type can be optimized to be foldl1' min.

Now what if we switched two lines, maybe during a refactoring, so that it was as follows.

code:
    min _                NegativeInfinity = NegativeInfinity
    min NegativeInfinity _                = NegativeInfinity
    min (Foo x)          (Foo y)          = Foo (min x y)
Now our function is not strict in its first parameter. And suddenly that optimization is invalid, and we're back up to O(n) memory usage.


You might say, "Okay, just use foldl' all the time." Well okay, that might solve that set of problems. But just that one.

So that was some information about how it's easy to get a memory leak by being too lazy. So we can avoid those by being more strict, right? Erm, actually, it's just as easy to create memory leaks by evaluating too strictly, too.

Adbot
ADBOT LOVES YOU

TOO SCSI FOR MY CAT
Oct 12, 2008

this is what happens when you take UI design away from engineers and give it to a bunch of hipster art student "designers"
Strictness optimizations like foldl' vs foldl aren't part of the compiler, though; there's no magical transformation which will make "sum = foldl (+) 0" work, because the definition of foldl precludes them.

It's not like somebody ever looks at a piece of Haskell code and wonders "gee, how much memory will this use?", and it certainly doesn't depend on compiler optimizations. The only compiler optimization which can change big-O behavior is stream fusion, which is performed only when requested by the code.

Most of the features you complain about are compiler-specific extensions, or have been removed from the language. This is the actual list of features, which I don't find particularly complex:

quote:

do notation, list comprehensions, pattern guards

do-notation is brain-dead simple to understand. List comprehensions and pattern guards are a bit more unusual, but hardly anywhere near LINQ.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply