Difference between abstract def and def

abstract def is mainly used with modules or inheritance to require that includers/children implements that method.

https://play.crystal-lang.org/#/r/7ar8

What’s wrong with this code?

class LogInterface
   def write(string : String)
   end
end


class StdoutLogger < LogInterface
end

No errors, no added abstract keyword.

An abstract class is a class that has to be inherited. You can not instantiate an abstract class. By the same token and abstract method has to be implemented by child classes. When you define an abstract method you don’t put any logic in it, you just define the parameters that the method is expected to receive, and possibly the expected response type. For instance

abstract class Foo
  abstract def bar(text : String) : Array(String)
end

def Baz < Foo
  def bar(text : String)
    string.split(" ")
  end
end

def Boof < Foo
  # This will not compile because it doesn't implement `#bar`
end

def fun(foo : Foo)
  pp foo.bar # This would work because the class `Foo` has a `#bar` method
end

Why would a developer want to create a class that has to be inherited though?

Also, when a developer is writing their classes and defs, isn’t this simultaneously creating their API/Specification as well?

To add: if you look at abstract struct MySql::Type from crystal-mysql, there seems to be a ton of logic here.

I appreciate the replies, but I’m still deeply confused and don’t understand the use case for this keyword.

Database adapters are a good example. You have a Base class that contains all the methods that the adapters need to include, then each adapter is free to do things their own way as long as they all have the necessary methods.

Look at Granite::Adapter::Base as an example.

1 Like

This makes sense, actually.

Why is it called abstract, though?

Shouldn’t it be called something else more clear? Abstract is quite ambiguous…

Because that’s what it is, it’s abstract. The literal definition of abstract is existing in thought or as an idea but not having a physical or concrete existence. I don’t think you can be much more clear than that.

It’s also a well known term in programming. Several languages have abstract classes and methods.

1 Like

That’s weird to me. That definition of abstract does not even remotely define what it’s actually doing in code, though.

It’s setting requirements needed for an inheritance to function correctly? That’s neither existing in thought or an idea, it’s the totally opposite. It’s concretely and explicitly written out…

Sure it does. You are defining a class that exists only as a concept. You can’t actually instantiate it. Same with abstract methods. They can’t be used until they are implemented. They are abstract.

Anyway, the other point is that it’s a commonly used and accepted pattern in programming. Java and several other languages do the same thing.

It’s not defining a class or def that “exists only as a concept”. It’s defining a class and def, that is a requirement for something that wants to inherent from it.

(assuming I understand your Database adapters analogy correctly)?

If true, I feel like abstract is a misnomer.

@watzon Thank you for the Database adapters example. That really hit the light bulb moment for me ;)

It does exist only as a concept though. Abstract classes can’t be instantiated. They only exist as a framework for other classes. I can’t think of a word that would be better, but that’s just me.

image

What is this?

Abstract classes can still define methods that will exist in child classes, but they themselves cannot be instantiated.

If they cannot be instantiated, why is initialize allowed inside them?

Because it defines an initialize method for child classes

Those “child classes” are the ones that must have the correct methods from the main abstracted class, corect?

@watzon Bear with me please, I almost got it.

abstract class Animal
  property name = "Base Animal"
  
  def initialize()
    pp "THIS IS ONLY CALLED! AND I MEAN ONLY CALLED: IF Dog.new is executed"
  end
  
end


class Dog < Animal
  def say_hello
    pp self.name
  end
end


pet = Dog.new

pet.say_hello

Dog is one of those “child classes”, right?

Correct. Any abstract method must be defined by the child class, any non-abstract method will be automatically included in the child class and will be usable by it. A simpler example of an abstract class in action is Cadmium’s Tokenizer class.

module Cadmium
  abstract class Tokenizer
    abstract def tokenize(string : String) : Array(String)

    def trim(arr)
      if arr[0] == ""
        arr.shift
      end

      if arr[-1] == ""
        arr.pop
      end

      arr
    end
  end
end

As you can see it defines one abstract method tokenize which all tokenizers have to include. It also defines the method trim which all tokenizers will have by default.

And yes, Dog is one of those child classes.

So the initialize in an abstract class, is only executed on the classes that inherit from it. It’s not actually being executed on the abstract class itself (because an abstract class) cannot instantiate itself.