2

first time poster. I've been using Java for a few years now, and have decided to learn D. In Java, you can declare a class with a generic type, and create a new object from that class. Like:

public class foo<T>
{
    public foo() { ... }
}

and then simply call foo<String> f = new foo<>();. I tried to implement the same in D, but I got a compile error like: "class core.collection.RingBuffer.RingBuffer(T) is used as a type". Looking at the tutorials for D, I have found that generic programming is implemented using templates. However, I cannot make heads or tails of the official tutorials/docs. Could someone please explain it to me? Thanks.

foxesque
  • 590
  • 6
  • 12
Straivers
  • 349
  • 1
  • 9

3 Answers3

5

That error comes when you don't instantiate the template on the right hand side - it complains "foo is used as a type" because foo itself isn't a type yet, it is a template for a type. That means it doesn't become an actual type until instantiated with !(arguments).

Your Java code of new foo<>() isn't exactly how it would be in D: in D, you need to give the type over there on the right hand side.

So try:

foo!string f = new foo!string();

or

foo!(string) f = new foo!(string)();

The parenthesis around the template arguments, following the !, are optional if there is just a single word after it, so both of those mean the same thing.

Writing the type twice isn't required in D, but instead of leaving it out of the right side, you can leave it off the left side with type inference. This will compile too:

auto f = new foo!string();

and that's pretty common in D.

he_the_great
  • 6,554
  • 2
  • 30
  • 28
Adam D. Ruppe
  • 25,382
  • 4
  • 41
  • 60
  • Thank you for clearing it up for me. However, the reference pages show that classes can be declared in templates? How does that work? – Straivers Feb 21 '15 at 14:14
  • 2
    `class foo(T) {}` is actually just shorthand for `template foo(T) { class foo {} }` and `foo!(T)` will automatically expand to `foo!(T).foo`. That probably makes it more confusing.... but the rule is that a template can have any declarations inside it using the template arguments. When you instantiate one, the template member with the same name as the template is automatically picked unless you specify something else. Other members can be used they are just more private. Those two facts combined means a template class is the same as a template with just one class inside it. – Adam D. Ruppe Feb 21 '15 at 14:22
  • So if I have a class that should always be instantiated to the type of another, can I just put both of them in the same `template` block? – Straivers Feb 21 '15 at 14:30
  • Yes, though that isn't always ideal because accessing it from the outside will take a bit more work. But if it exists just to help the main one, it is easy to use there and is a nice solution. – Adam D. Ruppe Feb 21 '15 at 14:32
5

Here is a minimalistic Java code using generics:

class Foo <T>
{
    public Foo (String arg) {System.out.println ("Hello, " + arg + "!");}
}

public class TestClass
{
    public static void main (String [] args)
    {
        Foo <String> f = new Foo <> ("Alice");
        Foo <String> g = new Foo <String> ("Bob");
    }
}

Here is its D equivalent:

import std.stdio;

class Foo (T)
{
    public this (string arg) {writeln ("Hello, " ~ arg ~ "!");}
}

void main ()
{
    auto f = new Foo !(string) ("Alice");
    Foo !(string) g = new Foo !(string) ("Bob");
}

These are just complete compilable examples. The reasoning is explained in Adam D. Ruppe's answer.

Community
  • 1
  • 1
Gassa
  • 8,546
  • 3
  • 29
  • 49
0

...and with default argument

template DataList( Data = string )
{
    class DataList
    {
        Data data;

        this()
        {
            // ...
        }
    }
}

// 
auto list = new DataList!string();

// readable
alias DataList!string List;

auto l = new List();
Vitaly Fadeev
  • 886
  • 10
  • 13