05 Mar, 2009, KaVir wrote in the 41st comment:
Votes: 0
Stormy said:
Like I said though, I don't see the difference between Mobile#save and Mobile#cmd_who(arg).


You need access to the mobile's private data when saving, but not when performing a command.

Furthermore, certain commands may be usable by players who don't have a mobile instance. For example in my mud, the 'who' command can be used without needing to log on first.
05 Mar, 2009, Stormy wrote in the 42nd comment:
Votes: 0
Good examples. Points well taken.
05 Mar, 2009, elanthis wrote in the 43rd comment:
Votes: 0
The neat thing about multi-paradigm, dynamic languages with first-class functions (like Ruby, or Python) is that there are some other cool ways of handling commands besides either procedural or OO code. Using function generators is a pretty cool technique, especially in a language that has syntactic sugar for function modifiers like Python does.

def command(cmd, name, admin=False, guest=False):
def wrapper(user, params):
if admin and not user.isAdmin:
user.writeln(name, " requires administrator privileges.")
return False
if user.isGuest and not guest:
user.writeln(name, " requires you to login first.")
return False
cmd(user, params)
return True
return wrapp

@command("ban", admin=True)
def cmd_ban(user, params):
user.writeln("Banning that scumbag!")
# ban user specific in params[0]

@command("who", guest=True)
def cmd_who(user, params):
user.writeln("Current users:")
# send list of users to the user

@command("quit")
def cmd_quit(user, params):
user.writeln("Goodbye!")
user.disconnect()


For languages that don't have modifier sugar, it might look more like:

command(name: 'ban', admin: true, func: function(user, params) begin
// command's code
end)


It's very similar to what you might do in an OO fashion with a base Command class, but it's (IMO) cleaner and easier to grok. With classes, every command needs all that boilerplate to pull off teh same thing:

class CommandBan extends Command:
function requireAdmin() begin
return true
end

function getName() begin
return "ban"
end

function command(user, params) begin
# finally able to write the damn command body
end
end
05 Mar, 2009, David Haley wrote in the 44th comment:
Votes: 0
I used something kind of like that to generate commands that take subcommands – no more silly "if first arg is 'set', do this, if it's 'list', do that, ……". Being able to treat functions as first class values is an amazingly convenient and powerful technique.
05 Mar, 2009, Tyche wrote in the 45th comment:
Votes: 0
David Haley said:
Well, you were right in some sense that there's no such thing as a global function since global functions are actually methods of a special object. But the distinction doesn't really matter in practice in this case. Maybe it would matter if you're doing something tricky or clever.


Sure it does..

def foo
end
foo # not an error
self.foo # error
Object.foo # error

while…
public
def foo
end
foo # not an error
self.foo # not an error
Object.foo # not an error

It's important enough to correct my own error.

Without going into a full explanation of Ruby there are a couple of other points:

  • ruby terminology differs from other OO languages

  • the object model differs from other OO languages


  • Classes, modules, and objects are interrelated. In the diagram that
    follows, the vertical arrows represent inheritance, and the
    parentheses meta-classes. All metaclasses are instances of the
    class `Class'.

    +——————+
    | |
    Object—->(Object) |
    ^ ^ ^ ^ |
    | | | | |
    | | +—–+ +———+ |
    | | | | |
    | +———–+ | |
    | | | | |
    +——+ | Module—>(Module) |
    | | ^ ^ |
    OtherClass–>(OtherClass) | | |
    | | |
    Class—->(Class) |
    ^ |
    | |
    +—————-+


  • method lookup is different from other OO languages

  • private, protected, public only apply to methods, and a different meaning than other OO languages

  • instance objects do not contain methods

  • instance methods are defined on class objects

  • class methods or singleton methods are defined on metaclasses

  • metaclasses are also commonly referred to as singleton classes, eigenclasses, or quaclasses

  • an object instance can have a metaclass

  • you can create a new class from an object

  • a class is an object

  • a class can have class variables, which are shared among derived classes

  • a class can have class instance variables, which are more useful because they are not shared

  • modules are namespaces

  • modules mixed into classes (include) insert proxy objects into method lookup

  • module can install methods on an object's eigenclass (extend)

  • an eigenclass can have an eigneclass can have an eigenclass …ad infinitum

  • the Singleton module implements the singleton pattern, which has nothing to do with singleton methods or singleton classes


  • Anyway, I'd expect anyone wanting to program in C++, C#, Ruby, Smalltalk, or whatever is going to first read up on all this.
    As a practical matter, many of the above concepts are often used in Ruby code.
    05 Mar, 2009, David Haley wrote in the 46th comment:
    Votes: 0
    Quote
    def foo
    end
    foo # not an error
    self.foo # error
    Object.foo # error

    while…
    public
    def foo
    end
    foo # not an error
    self.foo # not an error
    Object.foo # not an error

    This makes perfect sense under many (reasonable) interpretations of visibility, default scoping, etc. It's one reason why I don't like it when games are played with the global namespace and objects and all that – it can get confusing.
    14 Mar, 2009, shasarak wrote in the 47th comment:
    Votes: 0
    elanthis said:
    I personally disbelieve that OO is the only proper way to design software. Sometimes procedural programming is just what makes the most sense for the task at hand.

    In 14 years of work as a professional programmer I have yet to encounter a single example of that, but I'll take your word for it! :biggrin:

    elanthis said:
    Bjarne Stroustrup (original inventor of C++) had some good arguments about the multi-paradigm approach. He talked about why the std::string class does not have toupper() or substr() methods or anything of the sort. His basic argument is that methods like that aren't best conceptualized as methods (which are conceptually signals sent to a receiver to invoke a transition), but are instead very naturally thought of in a procedural (or even functional context). Operations like toupper() are very simply represented as a pure function, because they take an input and return an output with no side effects. Tacking procedural/functional operators into an OO model doesn't actually provide any real advantages, so why do it?

    If you want good guidelines on OO programming, the one type of person whose advice you should avoid at all costs is anyone who had anything to do with the creation of C++. It's a bastardised, abomination of a language that doesn't deserve to be described as "OO" at all. Quote from Alan Kay (http://en.wikiquote.org/wiki/Alan_Kay): "Actually I made up the term 'object-oriented', and I can tell you I did not have C++ in mind."

    Anyone who actually understands OO (i.e. someone who is not one of the creators of C++ :tongue: ) will understand instinctively that a function like ToUpper() should be an instance method on class String. If you ask "what should know about this aspect of the behaviour of strings?" the only answer there can possibly be in an OO environment is "stringsshould know about it - and nothing else should ever have to know how it works".

    It's important from a practical perspective, too. If class String has subclasses, how do you handle generating upper case versions of them? Obviously (in a statically typed language) you could use a global function which is overloaded for the different string classes, but the sane, OO way to do it is to have each string subclass handle it for itself. Not doing that means you're running away from using polymorphism, which is much of the point of using OO in the first place.

    elanthis said:
    If you look at most C# or C++ code, a lot of the time classes are used in a very non-OO way. Most singleton objects are generally just procedural code with encapsulation; the exact same functionality could be implemented (sometimes more cleanly) in purely-procedural code.

    That's true, but all that tells you is that people use Singletons when they shouldn't. :smile: The fact that some people programme OO incorrectly doesn't undermine its power when used properly.

    There are advantages to using Ruby- or Smalltalk-style class methods rather than global functions, too, in that subclasses can reference or override class methods defined on their superclasses. (You can't do this in C# version 2.0 - that is, you can't have a subclass override a static method defined on its superclass. You may be able to do this in later versions of C#, I'm not sure. I'm having to programme in C# version 2.0 at work right now, and not being able to do this is one of the most annoying aspects of the language for someone who is used to working in Smalltalk.)

    elanthis said:
    So… point is, there's nothing wrong with just having a bug function. If the function is meant to mutate instances of a specific class, then it should be a method. If it's just a routine that takes some input (including maybe certain objects) and then performs some operation (like send an email or insert a row into a table), then it makes perfect sense to make it just a 'static' function.

    That may be true; or it may be that there would be some advantages to having a Bug class which can be referenced from anywhere; or it could be that you simply want to to subclass some of the existing Exception classes; or maybe you actually need different classes to respond polymorphically to a bug message send (although, on the face of it, that seems less likely).
    14 Mar, 2009, JohnnyStarr wrote in the 48th comment:
    Votes: 0
    ok shasarak.
    since you seem to know allot about this, what would you suggest for player commands, this is a MUD forum isn't it? :grinning:

    do you think its better to make commands first class objects than using singleton methods?
    14 Mar, 2009, David Haley wrote in the 49th comment:
    Votes: 0
    Shasarak said:
    It's important from a practical perspective, too. If class String has subclasses, how do you handle generating upper case versions of them? Obviously (in a statically typed language) you could use a global function which is overloaded for the different string classes, but the sane, OO way to do it is to have each string subclass handle it for itself. Not doing that means you're running away from using polymorphism, which is much of the point of using OO in the first place.

    One function can handle it all, as long as your string class can do sane things like iterate over characters etc.

    I think that what Elanthis was getting at is that adhering too rigidly to the OO model can make for some unnecessary gyrations. I think that OO features are incredibly useful to have, and it's no surprise to me that new languages almost always have some kind of OO feature. But it's also not surprising to me that new languages also introduce ways of handling things functionally.

    Scala for example has a notion of implicit methods, which are not defined in the class itself. They happen to look like methods; for instance you can type 3! instead of !(3) to call the factorial function on 3. But it's implemented as (basically) a global function. It is basically a numerical equivalent of the toupper. Now, as it happens, you can't do this nicely with objects, since you cannot go edit the Integer class. You would have to make your own subclass, "FactorializableNumber" or something, and only use numbers derived from that if you wanted to be able to call factorial on them.

    Factorial is a very good example of something that in C++ (and many other languages – don't tell me how C++ is bastardized etc., it's irrelevant) would be inherently procedural and silly to implement as a method – as are most of the numerical functions. You could templatize it so that it would work on anything implementing multiplication.

    In some cases, like Ruby, you can go mess with things like the Number class, thereby providing the method to all subclasses. But there is no inherent reason for this to be a method. Arguing that something "should be" a method only because people who only do OO feel more comfortable that way is really a rather circular argument.

    The point is that if you can implement functionality on top of something's existing public interface, it can in fact be safer to leave it that way. If you add another method that thinks it needs to look at internals, you're only exposing said internals to yet more functions, and adding that many more places you need to fix things if you decide to change implementation. If you reuse the public interface, however, you only need to worry about the public interface changing – which is a problem orthogonal to all of this.
    14 Mar, 2009, Vassi wrote in the 50th comment:
    Votes: 0
    shasarak said:
    There are advantages to using Ruby- or Smalltalk-style class methods rather than global functions, too, in that subclasses can reference or override class methods defined on their superclasses. (You can't do this in C# version 2.0 - that is, you can't have a subclass override a static method defined on its superclass. You may be able to do this in later versions of C#, I'm not sure. I'm having to programme in C# version 2.0 at work right now, and not being able to do this is one of the most annoying aspects of the language for someone who is used to working in Smalltalk.)


    You can't do it in C# 3.0 either, nor do I think its in the spec for the next version (I forget if its 4.0 or 3.5, goofy microsoft versioning). One dirty hack I came across once involved making a static delegate, and then changing that delegate on a derived class if you needed it but that implies that you don't want to also use the default implementation. It also means the method signature can't change. Overall it seems like a bad idea, you'd be better off using Extension methods to add a static-like interface.
    16 Mar, 2009, shasarak wrote in the 51st comment:
    Votes: 0
    David Haley said:
    Now, as it happens, you can't do this nicely with objects, since you cannot go edit the Integer class. You would have to make your own subclass, "FactorializableNumber" or something, and only use numbers derived from that if you wanted to be able to call factorial on them.

    In a proper OO language like Smalltalk or Ruby :wink: you can modify base-classes (e.g. Integer). And very useful it is, too - quite definitely not simply a matter of being "comfortable for OO programmers". My application at work, for example, has its own object-relational mapper. To convert an object to SQL for storage purposes, you can send it #asSQLString, and it will return a string value appropriate for inclusion within a SQL query. So, for example, integer 2 would return the string "2" (suitable for inclusion in, say "where column_value=2"); a string like "hello" returns itself with added single quotes (suitable for "where column_value='hello'"); and a non-primitive object returns a string representing its primary key.

    Doing it this way means that if any specific class ever has to change its SQL representation, or if you add a new type of object that needs to represented in SQL (for example if your system supports dates and times separately and you want to add a date_time composite value) then the only code which has to be changed is the code that directly deals with the class in question. If you use a global function then not only does that function have to be uncomfortably complex to deal with all possible types that you might want to convert to a SQL string, but it means that you have to start editing a whole bunch of global functions as a result of changes to only one class. Avoiding that (and thereby minimising coding effort) is what OO is all about.

    David Haley said:
    don't tell me how C++ is bastardized etc., it's irrelevant

    Well, given that the point of OO is to reduce coding effort, I can't really see much point in using an OO language that still requires manual memory management. Who the hell has the time to explicitly deallocate pointers? :biggrin:

    A good term I came across a while back to describe a programming language is whether it is a "high-ceremony" or "low-ceremony" language. What that refers to is how much of the source code actually does something, as opposed to merely being something you need to type to get the programme to compile.

    C# is actually quite a high-ceremony language (lots of code that doesn't do anything). Smalltalk (which I work with) is very low-ceremony - almost everything you type actually has a function.

    For example, if you have a method which takes a collection of objects and returns the first one that is a weapon, in Smalltalk you'd do:

    findWeapon: collection
    ^collection detect: [:obj| obj isWeapon]


    The C# equivalent is:

    protected virtual Weapon FindWeapon(object[] collection) {
    return collection.Find(delegate (object obj) {return object.IsWeapon()); });
    }


    Great for lovers of brackets and semi-colons! :smile: C++ is a great deal worse even than C# in that respect.
    16 Mar, 2009, elanthis wrote in the 52nd comment:
    Votes: 0
    I like that term! high-ceremony.

    Now we just need a term for the signal-to-noise ratio of all that extra typing. :) Some very high-ceremony languages give you a lot in trade for all that extra typing, e.g. more safety (C#'s nullable pointers, for example) or C++'s RAII technique (which can be used for so much more than just easing memory management). Other languages have very little ceremony in their core language yet require you to write 5x as many unit tests as C# because you don't only have to test behavior but also have to test that you're using all the interfaces correctly, because the language won't/can't do it for you. e.g., in Python you may have a method that takes a string, but it lets you pass in any ol' object (you know, in case you for some random reason want to make an object that acts like a string)… but if the method calls some string method on that object which the object doesn't implement, you end up with a runtime error buried deep inside the internals of the module that in no way clearly states that Oops you didn't pass in an actual string (or something fully 100% conforms to the string behavior, anyway). You have to track it down yourself. Or add a ton of manual type-checking code to routines (which ends up taking way more typing than the type-specifiers in languages like C#).

    C++ is certainly high-ceremony and a lot of the typing it requires is mostly useless except to conform to the inflexible grammar. Especially before C++0x. :) C# is just as high-ceremony as C++ but much of the typing it asks of you has a very real effect (not in terms of *doing something* but in terms of specifying program intent and helping the compiler help you), even if that distinction is irrelevant to your needs at that moment.
    16 Mar, 2009, David Haley wrote in the 53rd comment:
    Votes: 0
    Shasarak, when the claim is "sometimes a function makes more sense than a method", giving an example of where it doesn't isn't an argument against the claim. It would be an argument against the claim that "functions always make more sense than methods". But nobody has made that claim here. :wink:

    And yes, many languages are certainly "high ceremony", but as Elanthis said, you're also getting something for all that pomp and circumstance. :smile:
    16 Mar, 2009, shasarak wrote in the 54th comment:
    Votes: 0
    elanthis said:
    Other languages have very little ceremony in their core language yet require you to write 5x as many unit tests as C# because you don't only have to test behavior but also have to test that you're using all the interfaces correctly, because the language won't/can't do it for you.

    Personally I loathe statically typed languages. I find the alleged type-safety is never really safe at all, it simply lulls you into just enough of a false sense of security that you forget to write your unit tests thoroughly. I certainly don't agree with your assessment that a dynamically-typed language requires 5x as much testing; in my experience there's almost no difference in the amount of testing required, but an enormous gain in terms of increased code legibility, greatly reduced coding time, and far more flexibility when it comes to creative use of polymorphism.

    When I first started using C# I found myself constantly having to cast objects to be types they actually already were just to make the compiler shut up! For example, almost the first thing I did involved a representation of a table which was able to render itself and its contents as HTML. I started with a completely abstract representation that had no concept of rendering at all (a Table with Rows of Cells). This supported concepts like adding a new row, and setting the contents of a cell. I then subclassed Table, Row and Cell, to produce a RichTable which has RichRows of RichCells. But, at that point, everything broke down because a Table's "rows" property was defined as being of type Row[]. You can't change the type of a property by overriding it. So that meant any time a RichTable referred to its rows property in a way that invoked a method defined on RichRow, I had to cast the rows property to be of type RichRow[] - even though that's what it already was!

    Obviously there are ways around that: I ended up defining the row class when creating a RichTable in the same way as one defines the type of a Dictionary (RichTable<RichRow>). But in a dynamically typed language it would never have been an issue: if you create a collection of RichRows there are no circumstances in which it doesn't behave like a collection of RichRows any time you need it to.

    (Note that the above example is deliberately simplified to get the point across. There was actually rather more going on than meets the eye, here: hence some other solutions which, on the basis of what I've said here, look reasonable wouldn't have worked out.)

    Duck typing (if it looks like a duck and quacks like a duck it probably is a duck) has always seemed far more logical to me: if the only thing needed for a function to execute correctly is that anything passed to it implements method X then it should simply work so long as anything passed to it actually does implement method X. Going through the process of formally defining an interface that includes method X and then labelling each class you might want to pass in to make it clear how it implements that interface is a huge amount of work for absolutely no gain. :smile:

    I know a lot of people (probably not including you :smile:) find dynamic typing scary, but I find the increased productivity hugely outweighs the extra testing effort.
    16 Mar, 2009, shasarak wrote in the 55th comment:
    Votes: 0
    staryavsky said:
    ok shasarak.
    since you seem to know allot about this, what would you suggest for player commands, this is a MUD forum isn't it? :grinning:

    do you think its better to make commands first class objects than using singleton methods?

    You should probably avoid using the word "singleton" in that context. What I guess you mean is a class method (roughly equivalent to a C# static method, only better :cool: ). "Singleton" is a term best reserved for the "Singleton Pattern" where it refers to an object rather than a method: that certainly wouldn't be appropriate, here, as there's no reason why you'd have a single object handling all commands of a certain type at one point in time, then remove that object and replace it with another of the same class doing the same job later. Those are the conditions where a "Singleton" is appropriate.

    As for the answer to your question, all I can really say is "it depends"; I don't know enough about what you're expecting your "player commands" to do to be able to answer. In terms of actually executing a command I would rather tentatively guess that you'd maybe want an instance of a class to do that. For example, you might have an object responsible for moving a player East (or trying to). It might have instance variables pointing to the player, and perhaps to his current environment. "East" might well also be a property of the object set at creation (likely an object, a subclass of Direction, rather than a string); it's also possible that MoveEast might a separate subclass of "MoveInADirection".

    It's often best just to try coding it one way and then, if it doesn't look right, refactor: no class model is ever even close to 100% right before you start coding. If you write good OO code (for example, keep methods to no more than 5 or 6 lines long, rarely pass more than one argument into a method, avoid switch statements at all costs, etc.) then how it should work will become more obvious as you go along.
    17 Mar, 2009, David Haley wrote in the 56th comment:
    Votes: 0
    Shasarak said:
    and far more flexibility when it comes to creative use of polymorphism.

    For some people, "creative" can mean "dangerous". I'm not sure if this is really what you mean, but you have been talking about flexibility as if it is something that comes at no cost whatsoever. I'm not saying that the cost outweighs the gain. I'm saying that it's not a free lunch.

    Shasarak said:
    When I first started using C# I found myself constantly having to cast objects to be types they actually already were just to make the compiler shut up!

    And many people introduce bugs into their software by thinking something is some type when it's really another, an error made even more perverse when the types share interface method names.

    Shasarak said:
    (Note that the above example is deliberately simplified to get the point across. There was actually rather more going on than meets the eye, here: hence some other solutions which, on the basis of what I've said here, look reasonable wouldn't have worked out.)

    It's hard for me to evaluate your example when I don't know what else is going on, since as you alluded to here there are many things that can be done to get around this. Your problem is a fairly common one with fairly standard solutions.

    Shasarak said:
    Going through the process of formally defining an interface that includes method X and then labelling each class you might want to pass in to make it clear how it implements that interface is a huge amount of work for absolutely no gain. :smile:

    I can't swallow claims like this. I mean, seriously, there's a reason why people are still designing statically typed languages, right? They're not all stupid people who are completely missing the point, right?

    I'm not some kind of anti-dynamic-language evangelist. I write code in dynamic languages all the time. Anybody who has read my posts here and elsewhere knows that I am a very strong proponent of using languages like Lua for implementing flexible solutions. But you're making it sound like static typing is never better than purely dynamic typing. It sounds like you're arguing that nobody should be working in statically typed languages. Now, I don't know what kind of code you write, and maybe in your work dynamic languages are more appropriate. But can you really make that claim for everything with as much confidence? (It's interesting that we've gone from object orientation in general to static vs. dynamic.)
    17 Mar, 2009, elanthis wrote in the 57th comment:
    Votes: 0
    You know, honestly, arguing dynamic vs static makes as much sense as arguing blonde vs redhead. :)

    For some tasks i vastly prefer dynamic languages. For others I vastly prefer static languages. For many tasks they both sucks donkey nuts. The perfect world would include a language that actually takes the best qualities of both; while there have been languages that do such things, most never gain critical mass and end up rather incomplete. A few go half the distance but end up being mostly classic statically-typed or classic dynamically-typed. No language has given me pure euphoria yet.

    I want a runtime capable of dynamic method invocation with optional type-annotation supporting non-inherited type contracts along with a full type-deduction engine for automatic method-chaining during duck-typed method invocations and with inferred typing for local variables, all with the usual niceties like closures and dynamic classes and so on, and on top of a modern runtime with tracing-JIT compilation and class-layout caching and richly-annotated bitcodes with the latest optimizer techniques. And a pony.

    There are plenty of neat language designs that really innovate and really make programming _fun_ and then they just kind of die off. Boo was a pretty nice language, for example; not perfect, no, but pretty fresh and pleasant to use anyway. It was really popular and written about a lot… and it just kind of faded out of the mainstream after a while. You can't get a job by learning Boo, but you can by learning VB.NET. That is how you know the world we live in is seriously ****ed up. :(
    17 Mar, 2009, David Haley wrote in the 58th comment:
    Votes: 0
    elanthis said:
    You can't get a job by learning Boo

    You could, you'd just have to make that job yourself in the form of a startup :tongue:

    Where I went to school, it sometimes felt like everybody and their brother & sister were doing startups. Best place to play with fun technology where you can start from scratch without being constrained by annoying details like production legacy. ('course, a lot of them start from scratch and die shortly thereafter… but hey.)
    17 Mar, 2009, quixadhal wrote in the 59th comment:
    Votes: 0
    Good luck doing a startup in this economy. Unless you're very wealthy and can fund yourself, or you are a very good salesman and can talk ROI-speak, investors are not likely to listen unless they hear things like "Microsoft" or "World of Warcraft Killer". :)
    17 Mar, 2009, elanthis wrote in the 60th comment:
    Votes: 0
    So I need to start drafting plans out for a Microsoft World of Warcraft Killer. Got it. I shall call it… Dark Age of Camelot! … wait.
    40.0/66