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
shrughes
Oct 11, 2008

(call/cc call/cc)

wellwhoopdedooo posted:

No, the essence of inheritance is that SubClass is a BaseClass. The conversion is done by pointer offsets or other aliasing methods, not conversion functions. You are high.

Your false distinction between some kinds of conversions and others is only preventing you from thinking constructively. You don't need some language's implementation of inheritance to encode the notion of an is-a relationship.

Adbot
ADBOT LOVES YOU

shrughes
Oct 11, 2008

(call/cc call/cc)
Inheritance

"To an external observer, inheritance of T from U is indistinguishable from the presence of a conversion function from T to U."

- Confucious

I was simply saying that from an external observer inheritance of T from U is indistinguishable from the presence of a conversion function from T to U.

And then people got all "oh no, inheritance is so much more than that" as if inheritance is also a mechanism used build definitions of types and functions without writing out a bunch of def foo(self) { return foo(convertToMySuperclass(self)); } definitions. Which was so surprising to me, being one of those high-on-Haskell types, I never knew that working-class languages could be so powerful!

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

shrughes posted:

To an external observer, inheritance of T from U is indistinguishable from the presence of a conversion function from T to U.

Doesn't the inheritance relationship also imply the lack of a conversion function in the other direction? Consider

code:
    subtype file,
        as string,
        where {-e $_}
    ;

shrughes
Oct 11, 2008

(call/cc call/cc)

Otto Skorzeny posted:

Doesn't the inheritance relationship also imply the lack of a conversion function in the other direction?

Well yeah, there is often an Unconvert : U -> Maybe<T>

tef
May 30, 2004

-> some l-system crap ->

shrughes posted:

Inheritance

"To an external observer, inheritance of T from U is indistinguishable from the presence of a conversion function from T to U."

- Confucious

yes but with my definition of inheritance i'm right :colbert:


(also *still* I don't see how the presence of a function implies implicit casting within the language - you can have inheritance without allowing implicit casts :3:)

shrughes
Oct 11, 2008

(call/cc call/cc)

tef posted:

(also *still* I don't see how the presence of a function implies implicit casting within the language - you can have inheritance without allowing implicit casts :3:)

It doesn't. I never said that.

tef
May 30, 2004

-> some l-system crap ->
Ahem.

shrughes posted:

Implicit casts are the same thing as inheritance.

It looks a lot like that to me

shrughes
Oct 11, 2008

(call/cc call/cc)

tef posted:

Ahem.


It looks a lot like that to me

It doesn't to me. I never said every language must have implicit casts. Instead of assuming I'm wrong (which is practically impossible) you should assume you've misinterpreted my statements.

ninjeff
Jan 19, 2004

inheritance is pretty useless anyway, just use decorators

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
There is a difference, but it's based on the fuzzy rule of Liskov substitution. Or rather, it's based on the quite solid rule of Liskov substitution, but languages generally have other rules which interact poorly with such substitutions, so instead we have to base this around vague ideas of what sane programmers would actually do.

So for example, Java's implicit conversion from int to long does not universally satisfy Liskov substitution because using an int instead of a long changes the type of an expression, which can impact overload resolution; but if you don't do semantically-distinguished overloads, it shouldn't matter. Similarly, upcasts can change overload resolution and member lookup, but if you're sane, it won't matter. But float->int conversions violate substitution basically as a matter of course.

NotShadowStar
Sep 20, 2000

shrughes posted:

Instead of assuming I'm wrong (which is practically impossible)

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

shrughes posted:

Inheritance

"To an external observer, inheritance of T from U is indistinguishable from the presence of a conversion function from T to U."

- Confucious

I was simply saying that from an external observer inheritance of T from U is indistinguishable from the presence of a conversion function from T to U.
This is only true of inheritance without polymorphism.

tef
May 30, 2004

-> some l-system crap ->

shrughes posted:

It doesn't to me. I never said every language must have implicit casts. Instead of assuming I'm wrong (which is practically impossible) you should assume you've misinterpreted my statements.

You said they were the same thing, so a language with inheritance would be a language with implicit casts, no?

Alternatively your idea of 'the same' has been influenced by php :v:

edit: you're violating the lsp :3:

Smugdog Millionaire
Sep 14, 2002

8) Blame Icefrog

shrughes posted:

Instead of assuming I'm wrong (which is practically impossible) you should assume you've misinterpreted my statements.

Instead of assuming you're wrong, I assume you're trolling.

shrughes
Oct 11, 2008

(call/cc call/cc)

Jethro posted:

This is only true of inheritance without polymorphism.

No it's not, the main point of the statement is that the form of polymorphism brought to you by inheritance is no different from a conversion function, and having no polymorphism.

Having T1, T2, and T3 being children of B1, overriding some foo method, is not special in any way. You could have an API that ostensibly lacks polymorphism, that's just as powerful, by having by having separate functions convertT1toB1(T1) -> B1, convertT2toB1(T2) -> B1, convertT3toB1(T3) -> B1. Then instead of passing a T1 to a function that expects a B1 you just pass the value convertT1toB1(T1). Or, for the sake of convenience, your language can support implicit conversions.

All inheritance gives you is one mechanism for defining such conversion functions, that's all.

TasteMyHouse
Dec 21, 2006
erm, wouldn't that call B1::foo? you're assuming dynamic dispatch which isn't always the case. In languages where functions are bound at compile-time, polymorphism and type conversion are distinct.

shrughes
Oct 11, 2008

(call/cc call/cc)

TasteMyHouse posted:

erm, wouldn't that call B1::foo?

No because foo is virtual.

nielsm
Jun 1, 2009



shrughes posted:

No because foo is virtual.

Then your object is still of type T1 even if it masquerades as a B1. If it behaves as a T1 then it is a T1, even if the formal type is something else in the context.
In my world, a type is defined by the operations on it. If two objects with the same interface have different actual operations performed by otherwise identical calls, then they are of different types.

Impotence
Nov 8, 2010
Lipstick Apathy

NotShadowStar posted:

I've been working with Drupal a hell of a lot the last six months. The core developers behind it seem like reasonably intelligent people and understand PHP is a wretched language and keep it to the very basics: arrays, functions, very basic objects and it works okay-ish, if not excessively verbose. Unfortunately when I have to delve into PHP land I remember how god awful it its. It took me an entire afternoon to parse a CSV file because neither str_getcsv or fgetcsv could figure out new lines properly so it always just split CSV files into one gigantic flat array. Something that would take minutes to do in any other language.

Presenting the PHP global function namespace

e: HOW FAR DOWN THE HOLE DO YOU WANT TO GO

It works okay provided your newlines are at the end of a line and not within any value field ever

shrughes
Oct 11, 2008

(call/cc call/cc)

nielsm posted:

Then your object is still of type T1 even if it masquerades as a B1. If it behaves as a T1 then it is a T1, even if the formal type is something else in the context.
In my world, a type is defined by the operations on it. If two objects with the same interface have different actual operations performed by otherwise identical calls, then they are of different types.

So you say that string("hi") and string("hey") are of different types.

nielsm
Jun 1, 2009



shrughes posted:

So you say that string("hi") and string("hey") are of different types.

That's an interesting definition of "different behaviour".

Dicky B
Mar 23, 2004

edit: never mind i'm not getting involved in this

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

nielsm posted:

If two objects with the same interface have different actual operations performed by otherwise identical calls, then they are of different types.

Does that make the empty string (that is, the string that returns true when you call isEmpty()) of a different type to any other string?

They do have quite distinct behaviour in that regard.

shrughes
Oct 11, 2008

(call/cc call/cc)

nielsm posted:

That's an interesting definition of "different behaviour".

They seem to behave differently to me. For example, one of them returns 3 when you call size() on it, and the other returns 2. Also, if you call .charAt(1) you get a different result.

All values of type B1 behave the way a B1 behaves. Even when they got converted from a function convertabertawoo() that took a T1 value (which behaves the way a T1 behaves).

For example, suppose B1 = string and T1 = int. We can convert all ints to strings with convertIntToString(3) == "3" but some strings can't be converted back to ints.

Also, just like all superclasses and subclasses, they behave differently in some ways and the same in others. If you pass a string (converted from an int) or a convertIntToString(n) to printStringToStdout, they'll behave exactly the same. Similarly, if you call size(s) or size(convertIntToString(n)), size will work exactly the same.

So let's look at the specific case where virtual methods are involved. You define a virtual or abstract method foo on base class B1 and override it in subclass T1. What that does is it defines a function call_foo_B1 that takes a B1 and a call_foo_T1 that takes a T1. But more particularly, you've defined the convertT1ToB1 function to produce a B1 such that call_foo_B1 will behave on that value the way call_foo_T1 behaved on the original T1.

Now you're going saying that some object exists that is still of type T1 even though we're now calling it a B1. What does that even mean? It's certainly the case that the B1 value is not necessarily a bit-by-bit copy of the T1 value. We need to perform some elementary arithmetic to convert between them. So we need to perform an actual manipulation to convert it back to a T1. But maybe you're thinking "Oh, but the part that does change is just the pointer, they're both pointers to underlying objects." Probably, but that's a pure implementation detail. Similarly with int and string, it takes some elementary arithmetic to convert from one to another. The fact that inheritance creates values that get converted at worst by some manipulation of pointer offsets is just a function of how compilers implement the types and conversion functions defined by inheritance.

nielsm
Jun 1, 2009



shrughes posted:

:words:

I guess I see the logic. It just doesn't seem like a terribly useful mental model to me, though it surely can be useful in some formal proof situations.

1337JiveTurkey
Feb 17, 2005

nielsm posted:

I guess I see the logic. It just doesn't seem like a terribly useful mental model to me, though it surely can be useful in some formal proof situations.

Any place where infinitely many degenerate types serves as a useful model is equivalent to a typeless one. Literally every function becomes a cast from one type to another. It's frankly pointless.

shrughes
Oct 11, 2008

(call/cc call/cc)

1337JiveTurkey posted:

Any place where infinitely many degenerate types serves as a useful model is equivalent to a typeless one. Literally every function becomes a cast from one type to another. It's frankly pointless.

What model is that? It's certainly not the one I was talking about (which just pooh-poohs subtyping).

Jethro
Jun 1, 2000

I was raised on the dairy, Bitch!

shrughes posted:

:words:
So inheritance is just an implicit cast assuming you've designed your types to behave as if they used inheritance.

Scaramouche
Mar 26, 2001

SPACE FACE! SPACE FACE!

Don't remember if this was posted when it was originally written, but a nice vindication of most of what we discuss (except the PHP part, but I'm convinced no PHP programmer actually uses comments):
http://www.webmonkey.com/2011/02/cussing-in-commits-which-programming-language-inspires-the-most-swearing/

TasteMyHouse
Dec 21, 2006

Scaramouche posted:

I'm convinced no PHP programmer actually uses comments


This is looking at commit messages, not comments. Still, php devs probably don't use those either.

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

TasteMyHouse posted:

This is looking at commit messages, not comments. Still, php devs probably don't use those either.

ecommerce-mvc-cms-framework.fixed the colors.backup2.real.zip

Internet Janitor
May 17, 2008

"That isn't the appropriate trash receptacle."
I think that if they're using source control at all they probably aren't the worst of the PHP programmers.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
That sure is some pretty, pretty, HTML.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

220 instances of <div class="wrap" can't be wrong.

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.

Jesus loving asschrist, that is bad.

carry on then
Jul 10, 2010

by VideoGames

(and can't post for 10 years!)

Well, for free it seems dec-oh. http://muse.adobe.com/pricing.html

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer
(I apologize for the length of this post, but you really have to see this in all its glory.)


Ladies and gentlemen, I give you The Invoice Print File Join Method.


It starts out reasonable enough. There are 15 checkboxes that determine what types of invoices to print. Therefore there could be up to 15 files that have already been written to disk. So obviously we need 15 StreamReaders and 15 ArrayLists.
code:
            (initialization code snipped)
            StreamReader sr1;
            StreamReader sr2;
            StreamReader sr3;
            StreamReader sr4;
            StreamReader sr5;
            StreamReader sr6;
            StreamReader sr7;
            StreamReader sr8;
            StreamReader sr9;
            StreamReader sr10;
            StreamReader sr11;
            StreamReader sr12;
            StreamReader sr13;
            StreamReader sr14;
            StreamReader sr15;
            bool first = true;
            bool isHeader;
            string sLine;
            ArrayList alFile1 = new ArrayList();
            ArrayList alFile2 = new ArrayList();
            ArrayList alFile3 = new ArrayList();
            ArrayList alFile4 = new ArrayList();
            ArrayList alFile5 = new ArrayList();
            ArrayList alFile6 = new ArrayList();
            ArrayList alFile7 = new ArrayList();
            ArrayList alFile8 = new ArrayList();
            ArrayList alFile9 = new ArrayList();
            ArrayList alFile10 = new ArrayList();
            ArrayList alFile11 = new ArrayList();
            ArrayList alFile12 = new ArrayList();
            ArrayList alFile13 = new ArrayList();
            ArrayList alFile14 = new ArrayList();
            ArrayList alFile15 = new ArrayList();
Now we have to go through each file and add each line, unless it's a header. "PrintFiles" and "Headers" are variables defined on the local object, which is fortunately a form object! That way you don't have to look too far to find out what actually happens when the user press the button on the form.
code:
            int iCount = 0;
            foreach (string file in PrintFiles)
            {
                iCount++;
                if (iCount == 1)
                {
                    if (file != null)
                    {
                        sr1 = FileUtils.OpenFileRead(file, encoding);
                        while (sr1.Peek() != -1)
                        {
                            sLine = sr1.ReadLine();
                            isHeader = Headers.Contains(sLine);
                            if (first || !isHeader)
                            {
                                alFile1.Add(sLine);
                                first = false;
                            }
                        }
                        sr1.Close();
                    }
                }
                if (iCount == 2)
                {
                    if (file != null)
                    {
                        sr2 = FileUtils.OpenFileRead(file, encoding);
                        while (sr2.Peek() != -1)
                        {
                            sLine = sr2.ReadLine();
                            isHeader = Headers.Contains(sLine);
                            if (first || !isHeader)
                            {
                                alFile2.Add(sLine);
                                first = false;
                            }
                        }
                        sr2.Close();
                    }
                }
                ... (you get the picture)
This is where it gets good. You see, we now have to sort the lines!
code:
            ArrayList alSortFile = new ArrayList();
            int iChoosen = 0;
            int iFile1 = 0;
            int iFile2 = 0;
            int iFile3 = 0;
            int iFile4 = 0;
            int iFile5 = 0;
            int iFile6 = 0;
            int iFile7 = 0;
            int iFile8 = 0;
            int iFile9 = 0;
            int iFile10 = 0;
            int iFile11 = 0;
            int iFile12 = 0;
            int iFile13 = 0;
            int iFile14 = 0;
            int iFile15 = 0;
            while ((alFile1.Count >= iFile1 || iFile1 == 0) &&
                (alFile2.Count >= iFile2 || iFile2 == 0) &&
                (alFile3.Count >= iFile3 || iFile3 == 0) &&
                (alFile4.Count >= iFile4 || iFile4 == 0) &&
                (alFile5.Count >= iFile5 || iFile5 == 0) &&
                (alFile6.Count >= iFile6 || iFile6 == 0) &&
                (alFile7.Count >= iFile7 || iFile7 == 0) &&
                (alFile8.Count >= iFile8 || iFile8 == 0) &&
                (alFile9.Count >= iFile9 || iFile9 == 0) &&
                (alFile10.Count >= iFile10 || iFile10 == 0) &&
                (alFile11.Count >= iFile11 || iFile11 == 0) &&
                (alFile12.Count >= iFile12 || iFile12 == 0) &&
                (alFile13.Count >= iFile13 || iFile13 == 0) &&
                (alFile14.Count >= iFile14 || iFile14 == 0) &&
                (alFile15.Count >= iFile15 || iFile15 == 0))
            {
Everything that follows lies inside this while-loop.

The following code ensues for each file, i.e. 15 times:
code:
                if (alFile1.Count > 0 && iFile1 <= alFile1.Count && (iChoosen == 0 || iChoosen == 1))
                {
                    if (iFile1 < alFile1.Count)
                    {
                        string[] values1 = alFile1[iFile1].ToString().Split(';');
                        if (alSortFile.Count < 1)
                        {
                            alSortFile.Add(StringUtils.Format("{0,6}{1,6}{2,6}{3,6}",
                                StringUtils.IsEmpty(values1[63].ToString()) ? " " : values1[63].ToString(),
                                StringUtils.IsEmpty(values1[65].ToString()) ? " " : values1[65].ToString(),
                                StringUtils.IsEmpty(values1[64].ToString()) ? " " : values1[64].ToString(),
                                StringUtils.IsEmpty(values1[43].ToString()) ? " " : values1[43].ToString()));
                        }
                        else
                        {
                            alSortFile[0] = StringUtils.Format("{0,6}{1,6}{2,6}{3,6}",
                                StringUtils.IsEmpty(values1[63].ToString()) ? " " : values1[63].ToString(),
                                StringUtils.IsEmpty(values1[65].ToString()) ? " " : values1[65].ToString(),
                                StringUtils.IsEmpty(values1[64].ToString()) ? " " : values1[64].ToString(),
                                StringUtils.IsEmpty(values1[43].ToString()) ? " " : values1[43].ToString());
                        }
                    }
                    else
                    {
                        if (alSortFile.Count < 1)
                        {
                            alSortFile.Add(string.Empty);
                        }
                        else
                        {
                            alSortFile[0] = string.Empty;
                        }
                    }
                }
As far as I can tell the contents of this if-statement are 100% identical for each file except for the variable names and such. Don't even ask me what the significance of 63, 65, 64 and 43 is.

Now we have to find the iChoosen file:
code:
                iChoosen = 0;
                iChoosen = SortFiles(alSortFile,
                    (alFile1.Count > 0 && iFile1 < alFile1.Count) ? alFile1[iFile1].ToString() : string.Empty,
                    (alFile2.Count > 0 && iFile2 < alFile2.Count) ? alFile2[iFile2].ToString() : string.Empty,
                    (alFile3.Count > 0 && iFile3 < alFile3.Count) ? alFile3[iFile3].ToString() : string.Empty,
                    (alFile4.Count > 0 && iFile4 < alFile4.Count) ? alFile4[iFile4].ToString() : string.Empty,
                    (alFile5.Count > 0 && iFile5 < alFile5.Count) ? alFile5[iFile5].ToString() : string.Empty,
                    (alFile6.Count > 0 && iFile6 < alFile6.Count) ? alFile6[iFile6].ToString() : string.Empty,
                    (alFile7.Count > 0 && iFile7 < alFile7.Count) ? alFile7[iFile7].ToString() : string.Empty,
                    (alFile8.Count > 0 && iFile8 < alFile8.Count) ? alFile8[iFile8].ToString() : string.Empty,
                    (alFile9.Count > 0 && iFile9 < alFile9.Count) ? alFile9[iFile9].ToString() : string.Empty,
                    (alFile10.Count > 0 && iFile10 < alFile10.Count) ? alFile10[iFile10].ToString() : string.Empty,
                    (alFile11.Count > 0 && iFile11 < alFile11.Count) ? alFile11[iFile11].ToString() : string.Empty,
                    (alFile12.Count > 0 && iFile12 < alFile12.Count) ? alFile12[iFile12].ToString() : string.Empty,
                    (alFile13.Count > 0 && iFile13 < alFile13.Count) ? alFile13[iFile13].ToString() : string.Empty,
                    (alFile14.Count > 0 && iFile14 < alFile14.Count) ? alFile14[iFile14].ToString() : string.Empty,
                    (alFile15.Count > 0 && iFile15 < alFile15.Count) ? alFile15[iFile15].ToString() : string.Empty, sw, iChoosen);
I won't show you what "SortFiles" does, but I can assure you that it doesn't sort any files!

We round things off with a nice, simple if-else chain.
code:
                if (iChoosen == 1)
                {
                    iFile1++;
                }
                else if (iChoosen == 2)
                {
                    iFile2++;
                }
                else if (iChoosen == 3)
                {
                    iFile3++;
                }
                else if (iChoosen == 4)
                {
                    iFile4++;
                }
                else if (iChoosen == 5)
                {
                    iFile5++;
                }
                else if (iChoosen == 6)
                {
                    iFile6++;
                }
                else if (iChoosen == 7)
                {
                    iFile7++;
                }
                else if (iChoosen == 8)
                {
                    iFile8++;
                }
                else if (iChoosen == 9)
                {
                    iFile9++;
                }
                else if (iChoosen == 10)
                {
                    iFile10++;
                }
                else if (iChoosen == 11)
                {
                    iFile11++;
                }
                else if (iChoosen == 12)
                {
                    iFile12++;
                }
                else if (iChoosen == 13)
                {
                    iFile13++;
                }
                else if (iChoosen == 14)
                {
                    iFile14++;
                }
                else if (iChoosen == 15)
                {
                    iFile15++;
                }
Let's hope we have to add another checkbox at some point, so we can take advantage of the flexibility of the code!

GROVER CURES HOUSE
Aug 26, 2007

Go on...

LOOK I AM A TURTLE posted:

(I apologize for the length of this post, but you really have to see this in all its glory.)

Let's hope we have to add another checkbox at some point, so we can take advantage of the flexibility of the code!

kill me :negative:

Contra Duck
Nov 4, 2004

#1 DAD

LOOK I AM A TURTLE posted:


Bravo :golfclap:

Adbot
ADBOT LOVES YOU

Ensign Expendable
Nov 11, 2008

Lager beer is proof that god loves us
Pillbug

LOOK I AM A TURTLE posted:



I saw this in production code before. Sadly, I fixed it and I can't be bothered to dig through subversion, but it was very similar. A dozen or so constructs, with hardcoded (identical) UI elements for each, a few boolean flags, three ArrayLists, some Strings. And lots and lots of if statements. When I rewrote the class to use a HashMap and proper OOP, I think it ended up being about a tenth of its original size.

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