Odd design decisions?

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
MHD
Posts: 630
Joined: Fri Mar 20, 2009 8:21 pm UTC
Location: Denmark

Odd design decisions?

Postby MHD » Tue Oct 04, 2011 9:34 am UTC

Have you ever encountered a language design feature you just though was odd?

I am currently looking at Ruby, and it seems to me that :symbols are largely neglected.
Why does Class.instance_methods return a list of strings and not symbols?
Why is it kosher to say x.responds_to? "method" in steadof x.responds_to? :method

I wonder...

C++ is, IMHO nothing but this topic.

Haskell has some oddities in the standard library, such as Monad not requiring Functor and Applicative, and the entirely absent Pointed class.
EvanED wrote:be aware that when most people say "regular expression" they really mean "something that is almost, but not quite, entirely unlike a regular expression"

User avatar
Sc4Freak
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Odd design decisions?

Postby Sc4Freak » Tue Oct 04, 2011 11:23 am UTC

Actually, there aren't that many oddities in C++ if you ask me. Plenty of gotchas, but C++'s gotchas are typically there for a reason - they're usually not just oversights. I think C++ is pretty well designed, and it definitely feels like a language that was engineered from the ground up whereas something like Python feels like it evolved more naturally over time (and parts of it are a mess and inconsistent as a result).

tliff
Posts: 9
Joined: Mon Aug 08, 2011 2:41 pm UTC

Re: Odd design decisions?

Postby tliff » Tue Oct 04, 2011 11:53 am UTC

MHD wrote:Have you ever encountered a language design feature you just though was odd?

I am currently looking at Ruby, and it seems to me that :symbols are largely neglected.
Why does Class.instance_methods return a list of strings and not symbols?
Why is it kosher to say x.responds_to? "method" in steadof x.responds_to? :method


Are you using 1.8? Those should all be symbols in 1.9

User avatar
headprogrammingczar
Posts: 3072
Joined: Mon Oct 22, 2007 5:28 pm UTC
Location: Beaming you up

Re: Odd design decisions?

Postby headprogrammingczar » Tue Oct 04, 2011 12:00 pm UTC

The Pointed type class in Haskell at least recently had reason not to be in the standard library. The only law that a Pointed instance would have to obey are a free theorem of fmap, which means any properly kinded type would be an instance.
What I never got was why parens of all things are the syntax for Perl list literals. Way to make the semantics of your language totally incomprehensible, guys.
<quintopia> You're not crazy. you're the goddamn headprogrammingspock!
<Weeks> You're the goddamn headprogrammingspock!
<Cheese> I love you

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Odd design decisions?

Postby Jplus » Tue Oct 04, 2011 12:27 pm UTC

I agree with Sc4Freak that C++ is in fact very well designed. However, I can think of an oddity in the newest version of the C++ standard, which is the attributes.

Java has some clear oddities, if you ask me. For example, the extreme verbosity, the strict separation between user defined types and builtin types, the restriction that containers of user-defined types can only store references to their contents, and the requirement that procedures are always member of a class. C# goes even further by requiring that a class is always wrapped in a namespace.

In Objective-C, I think the added syntax for OO programming looks crazy and totally unlike the rest of the language (i.e. plain C).

Iterator syntax in Lua is hard to wrap your head around, especially if you realize that it looks superficially like the iterator mechanism in Python while it works totally different.

In Python, loop-local variables are inserted into the surrounding scope. Also, surrounding an expression by parentheses may mean at least four different things, depending on the expression and the context.

Of course, if you want to find oddities esoteric languages are the place to be. :)
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
Robert'); DROP TABLE *;
Posts: 730
Joined: Mon Sep 08, 2008 6:46 pm UTC
Location: in ur fieldz

Re: Odd design decisions?

Postby Robert'); DROP TABLE *; » Tue Oct 04, 2011 1:36 pm UTC

Jplus wrote:C# goes even further by requiring that a class is always wrapped in a namespace.

C# 4.0 doesn't, and I'd be surprised if earlier versions did. (I just tried it)
...And that is how we know the Earth to be banana-shaped.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Tue Oct 04, 2011 2:20 pm UTC

IMO C++ has a bunch of examples of poor design. I'm not sure you'd call them odd, but export templates and exception specifications are two pretty clear examples. Some of the rules about where the typename keyword is required and prohibited are pretty crappy. (I ran into that when automatically generating code; I would argue that the fact that typename is required at all is poor design.) Though this is more of my opinion than the first couple, I strongly feel that the roles of, say, vector's [] and at() should be swapped (and then at should be renamed unsafe_at.) I could go on. Then of course there are a lot of things I think count as poor design given today's constraints which it inherited from C.

Carnildo
Posts: 2023
Joined: Fri Jul 18, 2008 8:43 am UTC

Re: Odd design decisions?

Postby Carnildo » Wed Oct 05, 2011 2:50 am UTC

I've never understood why C has two different operators for accessing structure members ('.' or '->', depending on if your variable is a pointer or not), when there is never a situation where it is valid to use both.

User avatar
mister_m
Posts: 34
Joined: Fri Feb 04, 2011 2:51 am UTC

Re: Odd design decisions?

Postby mister_m » Wed Oct 05, 2011 4:04 am UTC

Carnildo wrote:I've never understood why C has two different operators for accessing structure members ('.' or '->', depending on if your variable is a pointer or not), when there is never a situation where it is valid to use both.


Doesn't the arrow operator '->' represent a dereference, and then an access? Where the dot '.' is just an access?

Great Justice
Posts: 54
Joined: Sun Aug 15, 2010 5:28 am UTC

Re: Odd design decisions?

Postby Great Justice » Wed Oct 05, 2011 4:38 am UTC

MHD wrote:C++ is, IMHO nothing but this topic.

C++ has done remarkably well being internationally standardized, several times, while compiling most of C (not to mention advancing the C language itself), and maintaining backward compatibility with an enormous code base and compilers made by the giants.

In contrast: Java, controlled by only one company, started from scratch and for no good reason took only the appearance of the syntax to make it look like C++, then cranked the anal to 11.

Ergo, WTF to all of java, nevermind all the details. Squandered an opportunity to advance programming.
It usually isn't Congress or the State that tries to abridge free expression or free speech, [...] actually, in the present situation, the main threat to expression comes from public opinion.
~Christopher Hitchens

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Wed Oct 05, 2011 4:49 am UTC

mister_m wrote:
Carnildo wrote:I've never understood why C has two different operators for accessing structure members ('.' or '->', depending on if your variable is a pointer or not), when there is never a situation where it is valid to use both.


Doesn't the arrow operator '->' represent a dereference, and then an access? Where the dot '.' is just an access?

Yes, but why should it be that way? If the lefthand operand is a pointer, then . isn't valid, and if it's a structure, -> isn't valid. They could have easily used . in both cases, saying "if the left operand is a pointer, it dereferences first".

That being said, I do actually like the explicitness the two syntaxes present. And once C++ overloading enters the picture, it can be semi-convenient that they are different syntax.

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Odd design decisions?

Postby phlip » Wed Oct 05, 2011 5:08 am UTC

EvanED wrote:Yes, but why should it be that way? If the lefthand operand is a pointer, then . isn't valid, and if it's a structure, -> isn't valid. They could have easily used . in both cases, saying "if the left operand is a pointer, it dereferences first".

Yeah, but they're still doing completely different things. You may as well say something completely random, like "printing a string to an output stream should use the same syntax as left shifts, since it's never valid to use both". Such a system would be ridiculous. (But seriously... iostream: WTF.)

Also:
headprogrammingczar wrote:What I never got was why parens of all things are the syntax for Perl list literals. Way to make the semantics of your language totally incomprehensible, guys.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Wed Oct 05, 2011 5:33 am UTC

phlip wrote:
EvanED wrote:Yes, but why should it be that way? If the lefthand operand is a pointer, then . isn't valid, and if it's a structure, -> isn't valid. They could have easily used . in both cases, saying "if the left operand is a pointer, it dereferences first".

Yeah, but they're still doing completely different things. You may as well say something completely random, like "printing a string to an output stream should use the same syntax as left shifts, since it's never valid to use both". Such a system would be ridiculous. (But seriously... iostream: WTF.)

Or 'static' in C++. Iostream I'll actually defend as being the least bad alternative, at least as it was known for a while. (Boost has stuff that may be better, but it just picks a different operator to overload.)

But more to the point, why is f(x) syntax a legal shorthand for (*f)(x) if f is a function pointer? Those are doing different things. (Actually I think in many ways that's pretty analogous to the . vs -> issue.)

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Odd design decisions?

Postby phlip » Wed Oct 05, 2011 8:01 am UTC

EvanED wrote:But more to the point, why is f(x) syntax a legal shorthand for (*f)(x) if f is a function pointer? Those are doing different things. (Actually I think in many ways that's pretty analogous to the . vs -> issue.)

That's a good point, actually. I know I'll usually use (*f)(x), to make it clear a function pointer is being used, but the shorthand version is certainly allowed...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
MHD
Posts: 630
Joined: Fri Mar 20, 2009 8:21 pm UTC
Location: Denmark

Re: Odd design decisions?

Postby MHD » Wed Oct 05, 2011 2:52 pm UTC

Okay, I agree that Java is pretty odd. So odd that it has effectively slipped my mind in the five months of mine saturated by Haskell.

I do however think that C++'s stream shift operators is a novel, if not well enough thought through (underconsidered?) idea. That Ruby use them for list appending makes more sense, and I am working on a language draft that uses them for data serialization (which imho makes a little more sense than ext streams).

Don't even get me started on Scala's oddities.
EvanED wrote:be aware that when most people say "regular expression" they really mean "something that is almost, but not quite, entirely unlike a regular expression"

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Wed Oct 05, 2011 3:27 pm UTC

For people who don't like iostreams, what do you perceive as the problems? Why do you say they're "underconsidered"? What would you suggest as an alternative, in the world without variadic templates that we had before just recently? (Or would you have added all the complexity of variadic templates much earlier)

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Odd design decisions?

Postby Jplus » Wed Oct 05, 2011 3:43 pm UTC

I find the iostreams approach to output and input much more sensible than the classical approach with formatted strings. It's safer and more readable, it looks better, and it might even be a bit more efficient.

By the way, not to start a flamewar, but I think it was a crazy idea to enforce using so many parentheses in Lisp. :P
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

Markus__1
Posts: 36
Joined: Wed Apr 20, 2011 6:42 pm UTC

Re: Odd design decisions?

Postby Markus__1 » Wed Oct 05, 2011 9:37 pm UTC

phlip wrote:
EvanED wrote:But more to the point, why is f(x) syntax a legal shorthand for (*f)(x) if f is a function pointer? Those are doing different things. (Actually I think in many ways that's pretty analogous to the . vs -> issue.)

That's a good point, actually. I know I'll usually use (*f)(x), to make it clear a function pointer is being used, but the shorthand version is certainly allowed...


As I see it, a function name is a compile time function pointer constant (or a kind of function pointer literal).
However, since the distinction between a function name and a function pointer name is subtle, using (*fp)() [not fp()] and fp=&f [not fp=f] is a good idea for readability.
The typical rarity of function pointers is another reason - the extra decoration calls out a special construct that merits extra attention instead of only distracting from the code flow.

lalop
Posts: 210
Joined: Mon May 23, 2011 5:29 pm UTC

Re: Odd design decisions?

Postby lalop » Thu Oct 06, 2011 1:09 am UTC

Jplus wrote:I find the iostreams approach to output and input much more sensible than the classical approach with formatted strings. It's safer and more readable, it looks better, and it might even be a bit more efficient.

By the way, not to start a flamewar, but I think it was a crazy idea to enforce using so many parentheses in Lisp. :P


I feel like Lisp would be easier to read if there was some kind of variation in the parentheses. Perhaps I just need practice, though..

Sagekilla
Posts: 382
Joined: Fri Aug 21, 2009 1:02 am UTC
Location: Long Island, NY

Re: Odd design decisions?

Postby Sagekilla » Thu Oct 06, 2011 1:11 am UTC

Someone mentioned the export keyword earlier on, and I have to say I wish more compilers actually supported it.

Templates in C++ can be extremely weird and awkward, more so than they need to be. I wanted to be able to store a
complete interface within a header file, and then put all the implementation details within the cpp file.

Only problem was that since my class was templated, I had to specify the specific versions I wanted to instantiate within
my cpp file before I could even use them.

If that damned export keyword was supported, I could just toss it right in front of my class definition and everything would
be great. But nooo, only Borland C++ supports that.

That being said, I still think C++ is a well designed language. Not to mention one of my favorite ones to work in.

With regards to the typename requirement that was mentioned earlier, there was a question up on SO that actually tackled
that specific issue. It turns out the typename is required because the compiler needs to know it. Without it the compiler can't
properly resolve the types, IIRC.
http://en.wikipedia.org/wiki/DSV_Alvin#Sinking wrote:Researchers found a cheese sandwich which exhibited no visible signs of decomposition, and was in fact eaten.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Thu Oct 06, 2011 1:42 am UTC

Sagekilla wrote:Someone mentioned the export keyword earlier on, and I have to say I wish more compilers actually supported it.

Templates in C++ can be extremely weird and awkward, more so than they need to be. I wanted to be able to store a
complete interface within a header file, and then put all the implementation details within the cpp file.

Only problem was that since my class was templated, I had to specify the specific versions I wanted to instantiate within
my cpp file before I could even use them.

If that damned export keyword was supported, I could just toss it right in front of my class definition and everything would
be great. But nooo, only Borland C++ supports that.

Comeau. :-) (And Intel if you give it an --experimental flag or something I think.)

The problem with export is that of all the problems with templates, it solves basically exactly one: code organization. And while I don't want to minimize that benefit, the others still remain. Export can't help with long compile times, or having to distribute something which is functionally source, or error messages the size of War and Peace.

And the code organization benefits are not substantial... even now, you can split up declaration and definition into different files -- you just have to #include the definition file in the header.

That being said, I still think C++ is a well designed language. Not to mention one of my favorite ones to work in.

There are relatively few decisions I take issue with in isolation given the constraints of wanting strong backwards compatibility with C and with earlier versions of itself. However, the amalgamation... has a lot of problems.

I have a very love/hate relationship with C++. It's been trending more towards "hate" over time, but a lot of that is because I'm turning against non-memory-safe languages in general. (Most of the rest is because of compile times with heavy template use.)

With regards to the typename requirement that was mentioned earlier, there was a question up on SO that actually tackled
that specific issue. It turns out the typename is required because the compiler needs to know it. Without it the compiler can't
properly resolve the types, IIRC.

Believe me, I am well aware of why typename was added. (Google 'typename' -- I wrote the first hit.) I disagree that it's needed. Having it makes the compiler's job simpler, but by no means was that the only option. (Possibly more about the 2-phase lookup would have to change if it were removed, however.)

But even given that it's there, they added it in what I think is an obnoxious way. You can't say typename int for example. This can make automatically generated code more difficult, and when I was working on that project I mentioned before (which was a class project for a grad class, so a significant amount of time) dealing with typename issues probably occupied over half the time I spent on that project. Could have solved it in a day if you could just drop typename before any type name... but that would be to easy. (And while it's hard for me to say definitively, I suspect that this proposal would have made things either no more complicated or perhaps simpler for writers of C++ compilers.)

I mean, here are the rules about typename, as simply as I could summarize them:
  • Before unqualified types (dependent or not), typename is prohibited.
  • Outside of a template declaration, typename is prohibited.
  • Inside a template declaration, typename is optional before qualified but nondependent names. (E.g. both 'typename vector<int>::iterator' and just 'vector<int>::iterator' are legal.) However, it should probably be noted that an explicit specialization of a template is NOT itself a template, and so use of typename falls under rule 2, not this one.
  • Before a qualified dependent type, typename is required, except that when naming a base class in the base-specifier or a type in a constructor initializer list, typename is prohibited.


I mean, I feel like the standards committee is trolling us. It's optional before qualified but nondependent names inside of a template, but not an explicit (total) specialization of a template? It's required before a qualified dependent type, except if that type is a base class being named in the base-specifier or initialization list, in which case it's prohibited? Who the hell comes up with this nonsense?

Here's what the rules should be:
  • Before a qualified dependent name referring to a type, typename is required
  • Before other names of types, typename is optional

(Disclaimer: I wrote the above rules based on my reading of the C++03 standard, and it was largely inspired by one of the Addison-Wesley books. It's possibly (though unlikely) my statements are incorrect with regard to that standard, and a lot more possible that C++11 has changed the rules. I have no clue on that front.)

Turtlewing
Posts: 236
Joined: Tue Nov 03, 2009 5:22 pm UTC

Re: Odd design decisions?

Postby Turtlewing » Thu Oct 06, 2011 2:59 pm UTC

Jplus wrote:
Iterator syntax in Lua is hard to wrap your head around, especially if you realize that it looks superficially like the iterator mechanism in Python while it works totally different.

I found Lua iterators made a lot of sense (they's just a function that returns the next thing every time you call it). But I've never used Python so I might just have dodged the cognitive dissonance of keeping both in my mind at once

Sagekilla
Posts: 382
Joined: Fri Aug 21, 2009 1:02 am UTC
Location: Long Island, NY

Re: Odd design decisions?

Postby Sagekilla » Tue Oct 11, 2011 5:24 am UTC

EvanED wrote:Believe me, I am well aware of why typename was added. (Google 'typename' -- I wrote the first hit.)


I have to say, it's pretty cool to be able to say "Google this C++ keyword. See the first result? Yeah. I wrote that."
http://en.wikipedia.org/wiki/DSV_Alvin#Sinking wrote:Researchers found a cheese sandwich which exhibited no visible signs of decomposition, and was in fact eaten.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Tue Oct 11, 2011 5:31 am UTC

Sagekilla wrote:
EvanED wrote:Believe me, I am well aware of why typename was added. (Google 'typename' -- I wrote the first hit.)


I have to say, it's pretty cool to be able to say "Google this C++ keyword. See the first result? Yeah. I wrote that."

I'm pretty proud of it. :-) That being said, probably 90% of the reason it is so high is just because it's hosted on my CS dept's domain.

User avatar
Sc4Freak
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Odd design decisions?

Postby Sc4Freak » Tue Oct 11, 2011 8:44 am UTC

D:

I remember reading that page years ago when I was getting up to speed with C++. Small world.

User avatar
cerbie
Posts: 934
Joined: Sat Jul 05, 2008 5:14 am UTC
Location: USA

Re: Odd design decisions?

Postby cerbie » Wed Oct 12, 2011 5:29 am UTC

Turtlewing wrote:
Jplus wrote:
Iterator syntax in Lua is hard to wrap your head around, especially if you realize that it looks superficially like the iterator mechanism in Python while it works totally different.

I found Lua iterators made a lot of sense (they's just a function that returns the next thing every time you call it). But I've never used Python so I might just have dodged the cognitive dissonance of keeping both in my mind at once
The thing about them in Lua is that you get returned a function that returns the next thing each time you call it, not the first item in the list, and you are expected, if you do your own, to accept and store state in anonymous fashion, until the caller of the initializing function returns.

First time: xiter (X) -> xiter (X, state)
Subsequent times: xiter (X, state) -> Xstate+1, or state+1, Xstate+1 (if using typical i,v order)

http://lua-users.org/wiki/IteratorsTutorial

Notice all those local functions, and specifically, returning the local function, rather than say, a global function with a nice way of holding state in a table or some such? Kind of icky, compared to Python. It is not hard, but is not like most iterators that were created as language features. Lua went with the direction of using existing blocks of functionality, which makes sense in the context of Lua, the core developers of which want the least complexity possible for their given level of flexibility.
DSenette: (...) on the whole, even a trained killer cow is kind of stupid.

maafy6
Posts: 102
Joined: Wed Aug 22, 2007 10:43 pm UTC

Re: Odd design decisions?

Postby maafy6 » Fri Oct 14, 2011 6:49 am UTC

Code: Select all

// This function cannot throw any exceptions
void foo() throw();
// This function can throw whatever it wants
void bar();


Understanding the need for backwards compatibility, and the ability to look at throw() as throw empty-set = throw nothing, looking at the two in a vacuum it still makes no damn sense.

User avatar
RoadieRich
The Black Hand
Posts: 1037
Joined: Tue Feb 12, 2008 11:40 am UTC
Location: Behind you

Re: Odd design decisions?

Postby RoadieRich » Fri Oct 14, 2011 7:29 pm UTC

maafy6 wrote:

Code: Select all

// This function cannot throw any exceptions
void foo() throw();
// This function can throw whatever it wants
void bar();


Understanding the need for backwards compatibility, and the ability to look at throw() as throw empty-set = throw nothing, looking at the two in a vacuum it still makes no damn sense.

That makes a little more sense if you whitespace it better, so it's clear throw is a keyword rather than a function:

Code: Select all

void foo() throw ();


It would be even better if you could add "void" in there to be extra-explicit, but apparently that's a syntax error.
73, de KE8BSL loc EN26.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Odd design decisions?

Postby Jplus » Fri Oct 14, 2011 8:37 pm UTC

This syntax is deprecated in the new standard, anyway.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

Raucousbeard
Posts: 7
Joined: Tue Jun 12, 2007 10:19 am UTC

Re: Odd design decisions?

Postby Raucousbeard » Wed Dec 07, 2011 7:45 am UTC

EvanED wrote:
mister_m wrote:
Carnildo wrote:I've never understood why C has two different operators for accessing structure members ('.' or '->', depending on if your variable is a pointer or not), when there is never a situation where it is valid to use both.


Doesn't the arrow operator '->' represent a dereference, and then an access? Where the dot '.' is just an access?

Yes, but why should it be that way? If the lefthand operand is a pointer, then . isn't valid, and if it's a structure, -> isn't valid. They could have easily used . in both cases, saying "if the left operand is a pointer, it dereferences first".

That being said, I do actually like the explicitness the two syntaxes present. And once C++ overloading enters the picture, it can be semi-convenient that they are different syntax.


Actually, there is ambiguity. Consider the contrived case:

Code: Select all

struct Mundane {
   static const int I = 42;
};
struct Ambiguous {
   Mundane* operator->() { static Mundane m; return &m; }
   static const int I = 43;
};

int main() {
   Ambiguous a;
   printf("%d != %d\n", a.I, a->I);
}


More generally, the arrow operator is overloaded commonly for smart pointer implementations.

User avatar
phlip
Restorer of Worlds
Posts: 7572
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Odd design decisions?

Postby phlip » Wed Dec 07, 2011 9:06 am UTC

Didn't Evan just say that C++ operator-overloading changes things? The original question was for straight C, after all.

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Odd design decisions?

Postby EvanED » Wed Dec 07, 2011 3:34 pm UTC

Right. Carnildo's original question was about why C had those two operators in the first place. And unless Denis Ritchie had a time machine and looked forward to when a new language based on C was created with the ability to do operator overloading and decided to separate the two operators in C to allow that, the fact that you can overload -> in C++ to useful effect remains a happy(?) accident of history.

User avatar
ekolis
Posts: 76
Joined: Sat Nov 19, 2011 11:44 pm UTC
Location: Cincinnati, OH, USA
Contact:

Re: Odd design decisions?

Postby ekolis » Thu Dec 08, 2011 10:59 pm UTC

This might be Windows-API-specific, but surely I'm not the only one who gets annoyed with the various "secure", "fixed", and "final, no, really, we mean it this time" versions of standard library functions which are now deprecated. "Oh, you shouldn't be using sprintf anymore, you SHOULD be using sprintf_secure_v2_fixed_forrealthistime! Otherwise your program will be vulnerable to buffer overflows!" Well, that's all well and good, but why should I have to memorize the fancy names of the latest versions of the standard functions, and what happens to old programs that you don't have source code for? Why not just fix the original functions to begin with, instead of duplicating them and making a huge mess? Sure, you can say that some programs might rely on the legacy behavior... but when was the last time a buffer overflow was a GOOD thing?!

Disclaimer: I have never actually used any of these functions, because I've worked primarily with C#, VB.NET, and Java. But I've read some of the patch notes... :roll:

Now, as for weird stuff in languages I've actually USED... in C#, I can define an interface:

Code: Select all

public interface IStringifiable
{
    string ToString();
}


OK, now all objects in C# already implement ToString, so why can't I do this:

Code: Select all

IStringifiable position = new Point(42, 69);


The Point class, like all other objects, implements ToString, but because it doesn't *declare* itself as implementing IStringifiable (how could it? I just created IStringifiable myself!) I can't make this assignment, which is rather annoying, as it limits the usability of poorly abstracted libraries that you don't have the source for. (E.g. if some library had a ConstitutionClassCruiser class, as well as a MillenniumFalconPrivateer class, but no ISpaceship interface implemented by the two, and I want to apply common logic to both types of spaceships, I'd have to build in duplicate logic for the two cases.)

edit: oh, one other thing about C#... WHY the hell did they put stuff like Cartesian points and dependency properties in the PRESENTATION LAYER libraries?! I shouldn't have to reference WPF just to use things like that!
Reading posts on the xkcd forum makes me feel stupid.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11128
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Odd design decisions?

Postby Yakk » Thu Dec 08, 2011 11:09 pm UTC

ekolis wrote:This might be Windows-API-specific, but surely I'm not the only one who gets annoyed with the various "secure", "fixed", and "final, no, really, we mean it this time" versions of standard library functions which are now deprecated. "Oh, you shouldn't be using sprintf anymore, you SHOULD be using sprintf_secure_v2_fixed_forrealthistime! Otherwise your program will be vulnerable to buffer overflows!" Well, that's all well and good, but why should I have to memorize the fancy names of the latest versions of the standard functions, and what happens to old programs that you don't have source code for? Why not just fix the original functions to begin with, instead of duplicating them and making a huge mess? Sure, you can say that some programs might rely on the legacy behavior... but when was the last time a buffer overflow was a GOOD thing?!

Because the information that the new functions require is different than the information the old functions require.

sprintf, for example, is unsafe because it doesn't tell the function how long the buffer is. And there is no easy way to know how long the sprintf output will be without reimplementing sprintf. There is no practical way to take a program that doesn't provide this information and figure out what the safe length of the buffer "really is".

The new revision tells sprintf how long the buffer is.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Sc4Freak
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Odd design decisions?

Postby Sc4Freak » Thu Dec 08, 2011 11:31 pm UTC

ekolis wrote:This might be Windows-API-specific, but surely I'm not the only one who gets annoyed with the various "secure", "fixed", and "final, no, really, we mean it this time" versions of standard library functions which are now deprecated. "Oh, you shouldn't be using sprintf anymore, you SHOULD be using sprintf_secure_v2_fixed_forrealthistime! Otherwise your program will be vulnerable to buffer overflows!" Well, that's all well and good, but why should I have to memorize the fancy names of the latest versions of the standard functions, and what happens to old programs that you don't have source code for? Why not just fix the original functions to begin with, instead of duplicating them and making a huge mess? Sure, you can say that some programs might rely on the legacy behavior... but when was the last time a buffer overflow was a GOOD thing?!

Because you can't break binary compatibility. It's that simple. If you silently replaced sprintf with sprintf_s in the CRT, you'd break every application that ever used the old sprintf. The semantics of the two functions are not the same.

Now, as for weird stuff in languages I've actually USED... in C#, I can define an interface:

Code: Select all

public interface IStringifiable
{
    string ToString();
}


OK, now all objects in C# already implement ToString, so why can't I do this:

Code: Select all

IStringifiable position = new Point(42, 69);


The Point class, like all other objects, implements ToString, but because it doesn't *declare* itself as implementing IStringifiable (how could it? I just created IStringifiable myself!) I can't make this assignment, which is rather annoying, as it limits the usability of poorly abstracted libraries that you don't have the source for. (E.g. if some library had a ConstitutionClassCruiser class, as well as a MillenniumFalconPrivateer class, but no ISpaceship interface implemented by the two, and I want to apply common logic to both types of spaceships, I'd have to build in duplicate logic for the two cases.)

You're looking for a structural type system, of which C# doesn't have. C#'s type system is closer to C++ and Java than anything else. Adopting structural typing would have made C# a significantly different language to what it was intended to be - which was "Java but better".

edit: oh, one other thing about C#... WHY the hell did they put stuff like Cartesian points and dependency properties in the PRESENTATION LAYER libraries?! I shouldn't have to reference WPF just to use things like that!

There are many Point structs in .NET, used by different parts of the framework. For example, there's System.Drawing.Point (used in GDI and WinForms) and there's System.Windows.Point used specifically for WPF. XNA has Microsoft.Xna.Framework.Vector2.

There's a "duplication of functionality" because there is no one "Point" class that suits all needs. System.Drawing.Point uses integers because it was intended for legacy GDI drawing. System.Windows.Point uses doubles because it needs the precision for WPF graphics, and also supports declarations in XAML. Microsoft.Xna.Framework.Vector2 uses 32-bit floats and supports vector math, because it's intended to be used in game development and needs to interop with DirectX.

Dependency properties are also a WPF-specific feature. They rely on the WPF runtime to work, which is why they're a part of that library.

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Odd design decisions?

Postby Jplus » Fri Dec 16, 2011 6:39 pm UTC

Sc4Freak wrote:
Now, as for weird stuff in languages I've actually USED... in C#, I can define an interface:

Code: Select all

public interface IStringifiable
{
    string ToString();
}


OK, now all objects in C# already implement ToString, so why can't I do this:

Code: Select all

IStringifiable position = new Point(42, 69);


The Point class, like all other objects, implements ToString, but because it doesn't *declare* itself as implementing IStringifiable (how could it? I just created IStringifiable myself!) I can't make this assignment, which is rather annoying, as it limits the usability of poorly abstracted libraries that you don't have the source for. (E.g. if some library had a ConstitutionClassCruiser class, as well as a MillenniumFalconPrivateer class, but no ISpaceship interface implemented by the two, and I want to apply common logic to both types of spaceships, I'd have to build in duplicate logic for the two cases.)

You're looking for a structural type system, of which C# doesn't have. C#'s type system is closer to C++ and Java than anything else. Adopting structural typing would have made C# a significantly different language to what it was intended to be - which was "Java but better".

In fact, if you consider concepts an "implicit building block" of C++, then C++ does what you want. You can make them explicit with Boost.Concept.

As far as I know, Haskell is the only other language that has as full-fledged generic programming as C++. And concepts are explicit in Haskell, except that they're called typeclasses. If I remember correctly, you don't need to state explicitly that a type implements a typeclass, but you can do it anyway if the typeclass's default implementation of a function suits your needs.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

Raucousbeard
Posts: 7
Joined: Tue Jun 12, 2007 10:19 am UTC

Re: Odd design decisions?

Postby Raucousbeard » Fri Dec 16, 2011 6:44 pm UTC

Concepts were proposed for inclusion to the C++11 standard, but did not make it.

There is, however, a prototype gcc compiler called ConceptGCC that did implement them.

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=441

User avatar
sourmìlk
If I can't complain, can I at least express my fear?
Posts: 6393
Joined: Mon Dec 22, 2008 10:53 pm UTC
Location: permanently in the wrong
Contact:

Re: Odd design decisions?

Postby sourmìlk » Sun Dec 18, 2011 12:20 am UTC

C++'s use of the << and >> operators for streams always made me think of somehow pushing the data into a buffer, but I'm pretty sure that's misleading.

I think you've already gone over C++ specifications, so I don't need to cover that.

Why the hell does objective C use brackets with the same frequency Lisp uses parentheses? And why did they abandon constructors? Seriously, when you see a line in objective C that says something like [object init], it's calling a function explicitly labeled "init", it's not calling a constructor. And I don't like that it makes separation of interfaces and implementations mandatory.
Terry Pratchett wrote:The trouble with having an open mind, of course, is that people will insist on coming along and trying to put things in it.

User avatar
MHD
Posts: 630
Joined: Fri Mar 20, 2009 8:21 pm UTC
Location: Denmark

Re: Odd design decisions?

Postby MHD » Sun Dec 18, 2011 1:01 pm UTC

Jplus wrote:As far as I know, Haskell is the only other language that has as full-fledged generic programming as C++. And concepts are explicit in Haskell, except that they're called typeclasses. If I remember correctly, you don't need to state explicitly that a type implements a typeclass, but you can do it anyway if the typeclass's default implementation of a function suits your needs.


D does templated metaprogramming about twice as well as C++.

Haskell is polymorphic genric programming. It is way different in execution, but on some points similar in use. A Type Class in haskell serves as both Interface, OO Class and Concept all in one go.
EvanED wrote:be aware that when most people say "regular expression" they really mean "something that is almost, but not quite, entirely unlike a regular expression"

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Odd design decisions?

Postby Jplus » Sun Dec 18, 2011 2:47 pm UTC

MHD wrote:Haskell is polymorphic genric programming. It is way different in execution, but on some points similar in use. A Type Class in haskell serves as both Interface, OO Class and Concept all in one go.

No. Haskell classes offer polymorphism, data hiding and encapsulation. The typeclasses don't add any OO-ness to that (not even inheritance), only generics.

Interfaces are an "artifact" that tends to emerge in languages that aim to provide high modularity but lack both strong generics and multiple inheritance (e.g. Java, objective-C), in which they replace some of the functionality of both. For this reason, it's completely backwards to compare language features of C++ or Haskell to interfaces.

Anyway, I'll have a look into your claim that D has stronger generics than C++.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)


Return to “Coding”

Who is online

Users browsing this forum: Bing [Bot] and 5 guests