Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> In the Animal/Dog/Cat example, what happens if, in a separate module, if define a Snake class that doesn't have a `talk` method? There are several possibilities, sadly all pretty bad

The abstract class defines which methods every class that inherits from it must define by using abstract methods. If you write a class that inherits from an abstract class, and you do not define a method that the abstract class says that you absolutely must define, the compiler will raise an error for you. You can inherit from classes between modules.

> I'm asking about the errors that the language prevents, not the community's conventions.

I haven't actually tried it, definitely something I'll check out another time. I understand your concern though!



> The abstract class defines which methods every class that inherits from it must define by using abstract methods.

In their example, the type checker can infer that Animal has a `talk` method, even if it's never explicitly defined:

    abstract class Animal
      # no talk method here!
    end
    
    class Dog < Animal
      def talk
        "Woof!"
      end
    end
    
    class Cat < Animal
      def talk
        "Miau"
      end
    end
    
    class Person
      getter pet
    
      def initialize(@name : String, @pet : Animal)
      end
    end
    
    john = Person.new "John", Dog.new
In their own words, “Now the code compiles:”

    john.pet.talk #=> "Woof!"
Now, what happens if, in a separate module, I define a Snake subclass of Animal, without a talk method? What happens in this corner case isn't documented anywhere.

Type system design is very serious business, and can't be done by mindless trial and error. When a type system has a safety hole, patching it is pretty much guaranteed to break other people's code.


I can't seem to reply to your reply to this, but the error message has nothing to do with where a class is defined.

You can't compile a part of your application in crystal, there are no linked crystal libraries. You compile your whole app, will all class definitions. The compiler then will have all the type information to know if a method is missing in a subclass, when that method is used from a parent class.


Well, that's even worse. Whole-program compilation has positive aspects to it, like enabling more aggressive optimizations, but it should be strictly opt-in.

For future reference: The easiest way to reply to a message that doesn't have a “reply” link below, is to click on the “X minutes ago” link above.


Thank you! I didn't know that easy way to reply.

The compiler does some incremental compilation for the generated object files, so compile times are kept relatively small. Other than that, I don't think it makes a big difference for a developer except saving compile times. On the other hand, in this way you can't have a compiled library conflict so you have to "clean and rebuild" when this happens.

For example in Ruby there's no such thing as pre-compiling a gem, and every time you run an app the whole app is "analyzed" (parsed and converted to VM instructions), and so you can think in Crystal it's the same (except that it's compiled to native code)


Incremental compilation isn't a good alternative to actually separate compilation. If I implement a module Foo that depends on another module Bar, the only information I need is the interface Bar exposes, so I shouldn't have to wait until Bar is actually implemented to begin implementing Foo.


It will simply stop compiling the code and it will say "undefined method 'talk' for Snake". You will get a similar error if `talk` is defined as an abstract method in the base abstract class. So abstract methods are just a standard way to document this and to improve error messages. There's no safety hole here.


So the behavior of a subclass of an abstract class depends on whether both classes are defined in the same module or in different ones:

(0) If Snake is in the same module as Animal, the error is that “john.pet.talk” is a call to a nonexistent method.

(1) If Snake is in a different module from Animal, the errors is that Snake doesn't have a talk method.

This isn't nice.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: