In response to Bravo1
Bravo1 wrote:
Explain it to me Falacy, I'm quite intuitive.

http://www.byond.com/docs/guide/
"All we did was branch two new types of objects off of the basic turf. One is called floor and the other wall. The terminology of a family tree is often used to describe the relationship of the various objects defined here. Turf is the parent of floor and wall. The two children are siblings of each other. A child inherits all the properties of its parent and adds some of its own to distinguish it from its siblings. Both floor and wall are turfs because they are derived from the turf object type."
So we've been left with two situations. The one where either Falacy and Pop aren't on the same wavelength here about BYOND's hierarchy... or the one where every programmer who has touched BYOND, except Falacy, exist merely to annoy him and get everything wrong about how object oriented programming works.
Obviously not, if you need me to explain such a basic concept to you.

I'm standing by as an objective viewpoint on the debate, as such, I can't bring prior knowledge into the debate, only my judgement. So your insult just makes you look like an ass.

Fortunately though you're the only one to provide solid evidence to prove your side (The quote from the guide). So the debate is currently in your favor. If popisfizzy can return with evidence to expand or negate this then we will continue.
In response to Falacy
Falacy wrote:
Indeed, I refuse to accept that because it is completely and utterly wrong.

No, it's not. In fact, I proved that it's completely right. Unless you want to say one of the following statements about the Liskov Substitution Principle:
1) It is is wrong.
2) That my interpretation of the Liskov Substition Principle, as rendered into a formal mathematical logic statement, was incorrect or incomplete.

Well, 1) can not possibly be true. The LSP is a principle that defines a form of inheritance. A definition of something is, by its very nature, true. Thus, we must always assume LSP is a true statement.

How about 2? This is a little more iffy, as it involves a conversion of natural language into formal statements. Of course, the natural language statement is very formal, so this is easier. Liskov's original, formal statement is as follows: "If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T."

Now, let us break this down a bit:
1) "for each object o1 of type S there is an object o2 of type T" — This says we have two distinct objects of two not-necessarily-distinct classes S, T. Thus, let us call this statement C.
2) "for all programs P defined in terms of T the behavior of P is unchanged when o1 is substituted for o2" — This says that we can replace o1 with o2, and our program produces the same behavior. That is, if we take PT to be our program written in terms of T, and PT(x) to be some input for our program, then PT(o1) = PT(o2). We shall call this statement E.
3) "S is a subtype of T." — This says that the class indicated by S is a subclass of T. By this definition, T can be its own subclass, so it's possible S = T. This fact is trivial, and the in C can be modified slightly without affecting the overall nature of the proof. Let us call this statement R.

Thus, our statements can be as follows (with a few slight notational changes, to be clearer). "We have an object Si of class S, and an object Ti of class T" = C. Secondly, "PT(Ti) = PT(Si)" = E. Lastly, we have "S is a subclass of T" = R.

Note that C is a necessary, but insufficient, condition for the LSP. Thus, from this point out we will only be considering it when it is true.

Going by her formal statement, we can write this as LSP(C,R,E) := C and (E iff R)*. In formal English, "A relationship L is an inheritance relationship if there exist objects Ti of class T and Si of class S and for a program PT written in terms of T is such that PT(Ti) = PT(Si) if and only if S is a descendent of T under L"**. Different from what I had yesterday, yes.

But, remember that C is, by definition, true. It is always the case that (True and X) = X. Therefore, C and (E iff R) = True and (E iff R) = E iff R. In relatively-plain English, "S is a subclass of T if and only if the program acts the same". Furthermore, yesterday I had my values as P = "S subclasses T" and Q = "the program remains unaltered" (for adequate definitions of 'unaltered'). Fundamentally, P and Q are equivalent to E and R. Therefore, the statement I made yesterday is exactly equivalent to the Liskov Substitution Principle.

There, I proved that there was no mistake on my part about my logic. Now do you want me to go over yesterday's proof again? Okay, I will. And to be nice, I'll use the clearer form of of LSP(C,R,E) = C and (E iff R). In fact, I'll use the language for this demonstration.

Firstly, I will define a subtype relationship. Every class is identified by a typepath, which is a finite string defined by the regex (((\/)([A-z_]([A-z_0-9]*)))+(\/)?). A class K with a typepath Y is a subtype of another class J with a typepath T if and only if T is a substring of Y and the location of the substring T falls from 1 to n in Y, where 1 denotes the first character in a string and n denotes the length of T and the character at Yn is not a forward slash.

With that done, let's move on.


// Statement C. By the above definition, the class Class_S is a subtype of
// the class Class_T.

Class_T
proc/Foo()
world << "Bar"

Class_S
parent_type = /datum

var
Class_T
Ti = new

Class_S/Si = new


There, we have exactly what is called for in C. We have two classes, here called /Class_T and /Class_T/Class_S such that /Clss_T/Class_S is as subtype of /Class_T as I defined above, and we also two objects, Ti and Si.

// Prologue to statement E.

proc/P_t(Class_T/o)
return o.Foo()


Here we have E. This is an integral part of our proof. It is the PT(x) program. Thus, for our statement, it must be true that the results of P_t(Ti) and P_t(Si) are the same.

// Statement E.

mob/Login()
P_t(Ti)
P_t(Si)


This produces a runtime error. Therefore, E is false.

So, we have our final statement, R. Below is the truth statement of our table, displaying only when C = true.

/*
| C | E | R | C and (E iff R) |
+---+---+---+-----------------+
| T | T | T | T |
| T | T | F | F |
| T | F | T | F |
| T | F | F | T |
*/


Because C and LSQ(C,E,R) are true, by definition, and because E is false, we must conclude that R is false. Thus, our relationship (as defined above, a subtype relationship) is not and inheritance relationship. Because I can't post a tombstone here, I will simply end my now-rigorous proof as following: Q.E.D.

So wrong, in fact, that I gave up on even attempting to explain the correct concepts to you.

Hilarious. I've already written three proofs (my last one being highly formal and highly rigorous) demonstrating that a subtype relationship is not an inheritance relation.

After that post you made, I have to assume that you are literally retarded, or just maliciously trolling to spread idiotically false ideas.

Which one? The one where I used formal mathematics to prove a statement of mine? Or this one, where I used formal mathematics and formal language theory (some of it, at least) to prove my statement? That is, a rigorous proof, that is true beyond any doubt.

To say that type paths are not the inheritance system of BYOND is ridiculous.

Why?

A type path creates a parent child relationship

Only as the default behavior. Default. It can be overwritten, and thus this behavior is not true in all cases. This is why it's not inheritance.

where inheritance is derived.

... okay. That doesn't really make any sense, and it's just kind of being overly redundant because of its redundancy, but whatever.


Using parent_type to break this relationship is unarguably wrong.

Why is it wrong? You have given no reason, other than what amounts to 'because my gut says so'. I'm not the only one who would like this answered.

Have you ever actually read the DM guide that you constantly direct people to? Because it explains this simple concept very early on (in the very first chapter, in fact), not that it is difficult for anyone with half a brain to figure out on their own.

Yes, it does. It also doesn't state that this is the only allowed way, and that you absolutely can not use parent_type for inheritance. This is what is called lies to children. They are not wrong, but they're not right either. I'm sure you don't go around proclaiming the nonexistence of negative numbers or imaginary numbers, or that Newtonian mechanics is absolutely right and everything that tries to extend it is wrong (though, hey, maybe you are). This is another lie to children.

Clearly the DM guide is not written for a very-advanced audience. Why would it include discussion of relatively-advanced topics?

* The original statement uses 'if... then ...' phrasing. This would seem to indicate that I should have used implication. This is not true of definitions, though. A definition is an iff relation. As a demonstration, consider the successor function Su(x). First, P = "x = 3" and Q = "Su(x) = 4". By definition, Su(3) = 4, and Su is an injective function so Su(x != 3) != 4. Material implication of (P implies Q) would state that "If x != 3, then Su(x) = 4", which is not right. The actual relationship is (P iff Q), wherein the only true statements are "If x = 3, then Su(x) = 4" and "If x != 3, then Su(x) != 4".

** I do not explicitly state L here, but I mean it to be the subtype relationship I defined above. Furthermore, by "if and only if S is a descendent of T under L" I mean that if L is a hierarchical relationship (which it is), then under the hierarchy defined by L, S is a descendent of T or, equivalently, T is an ancestor of S.
Do you intentionally write these posts longer than your life story, with an excessive use of pointlessly technical looking nonsense, under the assumption that nobody will actually read them, and just assume everything you said was right?
In response to Falacy
Falacy wrote:
with an excessive use of pointlessly technical looking nonsense

There is not an ounce of nonsense in my post. If you find something you don't understand, which clearly there is much, feel free to ask questions. I can point you towards resources that would help you out. A good knowledge of logical connectives would be extremely helpful, as I use these extensively. This actually forms the core of my mathematics here. Some knowledge of regex would be useful, too.

under the assumption that nobody will actually read them, and just assume everything you said was right?

No. I would love if someone pointed out where I was wrong, because I could correct a misconception, which would help me in the future.

But, as it is, your ad hominem attacks, and attacks on the nature of the post, rather than criticisms of its content, do nothing to support your cause. I have demonstrated my proof. It is there for the world to see, and it is clear and unambiguous. If you can find a flaw in it, then indicate it. Until then, realize that you have been proven wrong. Your assumptions are invalid, and thus you have no stone to stand on.

[Edit]

In fact, let's have a bit of fun. A list of Falacy's Fallacies!

1) Shifting the burden of proof (though I've so-nicely cooperated).
2) Mind projection fallacy.
3) Moving the goalposts.
4) Red Herring.
5) Ad hominem.
6) Appeal to authority.
7) Appeal to consequences.
8) Appeal to motive.
9) Appeal to tradition.
10) Judgmental language.
11) Is-ought fallacy/reverse is-ought fallacy (maybe).
12) Straw man (before).
I've read it over and the proof checks out, unless he made a mistake that I missed.

Falacy?
I am not saying that parent_type doesn't effect inheritance, that is exactly what it does: "This variable is set at compile-time to specify the inheritance of an object type. Normally, a new type of object inherits its variables and procedures from the object type that contains it." It is important to note the use of "Normally" there, as that is pretty much the entire point of my argument. It is wrong to use parent_type for this purpose, as it breaks the natural relationships of BYOND types. I am not sure how much better I can explain that fact, as it should be blatantly obvious through the use of parent_type itself.
turf
Floor
//turf is the parent type of Floor
//Floor is a proper subtype of turf
//Therefore it inherits turf content
//The Floor and its contents can be referenced

turf
Floor
parent_type=/Fail
//Though Floor is still a subtype of turf
//It will no longer have turf as a parent
//It will inherit who knows what from who knows where
//This breaks the proper typing relationships of BYOND
//Neither the Floor type itself, nor its contents, can be reliably referenced
Sure, you could throw a bunch of "math" together in an attempt to make yourself look correct, or intelligent, or just in a long winded attempt that you hope nobody will read because you know you're wrong and have no proper way to defend yourself, but that doesn't make this practice any more acceptable. Your delusional "math" obviously doesn't remove the proper inheritance that BYOND type paths provide.
mob/verb/One()
var/thisVarIsAlwaysOne=1
thisVarIsAlwaysOne=2
src<<"1=[thisVarIsAlwaysOne]?"
Could I do what is demonstrated by that verb? Sure. Could I write "math" formulas that make it say one way or the other is always feasible? Sure. Is it smart or correct to create a variable that should always be 1, and then change it to 2? Apparently, this community has trouble figuring that out, but I'll leave it up to you.
So your argument is that using/changing the parent_type variable is wrong because it has no practical use?

Okay here you go:

Not using parent_type:
life
animals
mammals
great_apes
humans

mob/verb
Create_New_Life()
var/life/Plants=new

Create_New_Animal()
var/life/animals/Fish=new

Create_New_Mammal()
var/life/animals/mammals/Canines=new

Create_New_Great_Apes()
var/life/animals/mammals/great_apes/Gorillas=new

Create_New_Human()
var/life/animals/mammals/great_apes/humans/Jeff=new


Using parent_type:
life
parent_type=/obj
animals
parent_type=/life
mammals
parent_type=/animals
great_apes
parent_type=/mammals
humans
parent_type=/great_apes


mob/verb

Create_New_Life()
var/life/Plants=new

Create_New_Animal()
var/animals/Fish=new

Create_New_Mammal()
var/mammals/Canines=new

Create_New_Great_Apes()
var/great_apes/Gorillas=new

Create_New_Human()
var/humans/Jeff=new



Using parent_type can greatly simplify systems that use multiple subtypes with different naming contexts.

I can even use this method to create entire sections/files of code that have better separation and organization, making all my different object types quick and easy to find and to implement. Now I don't have to type out huge type strings just to create a specific object.

I already know what you're going to say next though: "Who would ever use that many subtypes? They must be stupid."

Perhaps the project calls for multiple types with multiple subtypes of each, this can help sort, create, and reference them easily.

So there is a valid use for changing parent_type. The only people who do it wrong are people who don't understand what it does and decide to use it anyways. So I guess you can stop claiming it's wrong to use or change parent_type because there's a perfectly good reason to use it.
The use of parent_type to simplify paths or sorting is mentioned in my topic about not changing it. Laziness is not a good reason to use a broken system that makes your code uninformative and/or confusing.

As for your example, there are better ways to handle that setup dynamically, instead of writing out multiple, redundant verbs that do nearly identical things. Then you would have to worry less about long type paths in the first place.
They were being used as examples of how you can simplify a type.

aka writing: var/human/Jeff=new

instead of var/life/animals/mammals/great_apes/humans/Jeff=new

of course, you probably knew that but decided to comment on it anyways without the need to. Unless you didn't understand what I was trying to do, it's a fairly simple example.

I checked out your example that you linked to

the problem is: You are constantly assuming that people are going to use parent_type to change the actual parent instead of using it for organizational purposes.

Explicitly setting the parent type allows you to put the object definition any place you want.
From the DM reference

parent_type is not meant to be used to change the parent_type, only to define it for organizational purposes.

The only one who seems to be using it to try to change the actual parent type is you.

You're looking at a car and saying "You shouldn't drive cars because you can use them to smash into people and kill them."

You're right that you can smash people and kill them but you're wrong that people should never use cars.

just like you're right that changing parent_type can fuck up your code and confuse things but you're wrong about the fact that it shouldn't be used because if you know what you're doing then it's completely fine.

Just because you think people are going to use something incorrectly doesn't mean they will.
In response to Bravo1
Bravo1 wrote:
parent_type is not meant to be used to change the parent_type, only to define it for organizational purposes.

A slightly more acceptable usage of it, though still an unnecessary one. Also, since this entire discussion started because of fizzle's bad tutorials, where he was indeed changing a type path's parent type with parent_type, I am going to stick with my arguments =P
What ever happened to the whole point of programming
(for those of us not making a career out of it) to be able to get shit-faced and do something cooler than your buddy (lib or not)? Y'all be takin' this too serious, yo.
In response to Falacy
I went away for a day and missed quite a lot.

Falacy wrote:
Except, you still used DM for everything. You may have created your own procs to perform these simple functions (which is the correct way to go in more advanced situations), but you're still just using oview() and basic subtraction in your extended example.

The actual implementation (using oview() or subtraction) is abstracted out from the code that uses it. When you write the special_attack() proc you don't have to be aware of how get_targets() or take_damage() are implemented, you only have to remember their arguments and return values. When you don't abstract out details like that programs get too complicated too quickly - they become difficult to work with.

This is a problem that many DM programmers run into and can't figure out how to deal with it. I suspect that most newbies think this is just what programming is about*. Abstracting out implementation details isn't an intuitive solution. Newbies won't figure out to program this way on their own. Libraries let you add some feature to your game very easily because they abstract out the details - this shows people the benefits of abstraction. By seeing how easy it is to use a library, they'll get the idea that they can write code that's that easy to use too.

* Most people think that code is super complex and that good programmers can instantly make sense of complex code and can memorize all details about a large project. That's not how it works. Good programmers write better code so there are fewer details that need to be memorized. This is an obvious misconception. Imagine what a 7 year old would think that a mathematician does. Someone who doesn't know much about math couldn't have a good idea of what higher level math is about.
Falacy, you should let this die. pif has given you mathematical proof that parent_type is fine and bravo has given you a very good practical reason to use it. I use it ALOT to derive subtypes of /atom/movable that wouldn't be considered an object or mob to help keep my code clean. It also helps avoid complicated type paths like bravo mentioned.

I honestly don't know why anybody is bothering discussing this with you, because every time somebody makes a good point, it seems to elude you. It's pretty clear that you didn't read pif's posts and that you just cherry-picked them for things that you could use to insult him.

[edit]
You should also take note that BYOND does parent_type behavior by default. All objects and mobs inherit from /atom/movable and all turfs and areas inherit from /atom. You can't avoid the parent_types.
In response to Falacy
Falacy wrote:
I am not saying that parent_type doesn't effect inheritance, that is exactly what it does

Good. You finally got this right.

"This variable is set at compile-time to specify the inheritance of an object type. Normally, a new type of object inherits its variables and procedures from the object type that contains it." It is important to note the use of "Normally" there, as that is pretty much the entire point of my argument. It is wrong to use parent_type for this purpose

This is a false dichotomy, as it implies there are only two valid possibilities: Something is either 'normal' or it is 'wrong'.

This is not the case. The proper dichotomy is 'correct' or 'incorrect' with regards to a formal grammar. BYOND does not have an explicit one (Well, Jp may have an explicit one, but that's beside the point), but it does have an implicit one in the compiler. That implicit formal grammar indicates that rewriting parent_type to modify inheritance is absolutely valid.

One problem is you muddle the two meanings of "that is wrong". When someone uses goto to try and write a loop, "that is wrong" means "that is sub-optimal and there are better ways to do it". When someone uses a goto to try and write, say, a conditional statement, then "that is wrong" means "it is not possible to do it that way". When asked to try and defend the former, you jump to the latter without justifying the latter.

as it breaks the natural relationships of BYOND types.

This is a variation of the naturalistic fallacy, and it seems like it may be specifically related to the is-ought problem. The 'natural' (i.e., default) state of DM is that the parent_type is assigned to the enclosing class. Does something being the default mean non-default options are wrong? No. I don't have the default BYOND icon right now. Does that mean I'm wrong? No. You don't have the default BYOND icon at the time of my writing this. Does that mean you're wrong? If you have tried to impart anything to BYOND, it's that you're never wrong, so I'm guessing, 'No'.

It also appears you are not realizing that the relation between classes and typepaths is analogous to the map-territory relation. The class is not the typepath. They are not the same thing. A typepath is simply an identifier for the class. This has important implications: A subclass and a subtype are not always the same class.

You may also do well to understand the allegory of the cave.

I am not sure how much better I can explain that fact, as it should be blatantly obvious through the use of parent_type itself.
turf
Floor
//turf is the parent type of Floor
//Floor is a proper subtype of turf
//Therefore it inherits turf content
//The Floor and its contents can be referenced


I'm not sure what exactly you're saying with some of this, though I'm going to assume by "contents" you're going to mean its members and/or subclasses, and by "referenced" I'm guessing you don't mean a reference.

turf
Floor
parent_type=/Fail
//Though Floor is still a subtype of turf


Yes, it's a subtype but not a subclass. Why is this a problem, other than the fact that you're breaking the semantics of the /turf type?

//It will no longer have turf as a parent

Indeed.

//It will inherit who knows what from who knows where

It will inherit from the class indicated by the /Fail typepath. As you're clearly unaware, it appears that there exists no language other than DM where it's possible to indicate the superclass of a class through any other way that it's 'direct identifier' (i.e., in this case 'Floor'). Here are examples from some common languages.

// C++

#include <string>
using std::string;

class SuperClass
{
public:
virtual string *Foo()
{
return new string("Alpha");
}
};

class SubClass : public SuperClass
{
public:
string *Foo()
{
return new string("Bar");
}
};


// Java

public class SuperClass
{
public String Foo()
{
return "Alpha";
}
}

public class SubClass extends SuperClass
{
@override
public String Foo()
{
return "Bar";
}
}


// Python

class SuperClass:

def Foo(self):
return 'Alpha'

class SubClass(SuperClass):

def Foo(self)
return 'Bar'

// This example may be slightly-off, as I have no experience with Python. Could
// an experienced Python developer verify this?


When instantiating the subclass, each and every one of these languages use only the identifier 'SubClass'. Outside of the class definition, there is no way that the superclass can be simply identified, for example, when instantiating. Do you know how programmers in these language learn where it inherits from, and how to use the class? They RTFM.

//This breaks the proper typing relationships of BYOND

I assume by proper typing relationship you mean "A superclass must be equal to its supertype". I want to know your justification for declaring this the 'proper typing relationship'. If you wish to appeal to authority, go ahead. I'll appeal to authority as well for my cause: The DM language itself violates this typing relationship. /turf has no supertype, but its superclass is /atom. /atom has no supertype, but its superclass is /datum.

//Neither the Floor type itself, nor its contents, can be reliably referenced

Why not? And furthermore, why is this even relevant?

Sure, you could throw a bunch of "math" together
Your delusional "math"

I was not aware that putting something in quotes made it immediately invalid, "Falacy".

If that's even your real name.

in an attempt to make yourself look correct, or intelligent, or just in a long winded attempt that you hope nobody will read

I'm not sure if you've used the internet, but typically the worst way to make sure no one reads something is by putting it on the internet.

because you know you're wrong and have no proper way to defend yourself,

Well, I had thought DM was, as a programming language, a formal language and thus was governed by formal language theory. Formal language theory is a mathematical discipline. It just seems to me that someone working in a mathematical discipline should be able to use mathematics to to justify themselves. In fact, when discussing the theory of a mathematical discipline, typically this is the best way to define themselves.

Or maybe the Pythagoreans should've just told Hippasus, "irrational numbers".

My entire proof is there for the world to read. You are entitled to read through it and point out any fundamental flaws that mean the proof is not correct. If you don't understand the language, that is not my fault. You are free to ask questions and use any resources you can find to assist you(Hint: You have the entire internet available to you). Until you do that, though, you are not entitled to just say, "No, you're wrong."

but that doesn't make this practice any more acceptable. Your delusional "math" obviously doesn't remove the proper inheritance that BYOND type paths provide.

I'm not sure if you understand how math works. A mathematical proof doens't change something, except maybe a view point. When Pythagorean theorem was proven millenia ago, it didn't just somehow 'create' a feature of mathematics. It just proved something that always was true. My proof has not 'removed' anything. It has simply shown that your belief of 'proper inheritance' (which, by-the-way, is formally equivalent to your statement of 'proper typing') is not valid given the current DM formal grammar.

mob/verb/One()
var/thisVarIsAlwaysOne=1
thisVarIsAlwaysOne=2
src<<"1=[thisVarIsAlwaysOne]?"

Could I do what is demonstrated by that verb? Sure. Could I write "math" formulas that make it say one way or the other is always feasible? Sure. Is it smart or correct to create a variable that should always be 1, and then change it to 2? Apparently, this community has trouble figuring that out, but I'll leave it up to you.

wat

I'm sorry, let me ask again.

wat
@Popisfizzy: That's an awful lot of text. All it comes down to is that experienced programmers define lots of object types. With that many object types it'd be too cumbersome to always write the full path. Instead, good programmers:

1. Pick good object names so they don't have to remember all inheritance that takes place (ArrayList implements the List interface, you don't say?).

2. Make objects such that all inheritances aren't important (it's not often important that all of my Java classes inherit from the Object class).

[insult snipped] When you design everything to fit the atom types BYOND provides it's only going to cause confusion to learn that you don't need to do that.
Page: 1 2 3 4