Thread overview
C++ to D
Mar 11, 2015
Dennis Ritchie
Mar 11, 2015
Kagamin
Mar 11, 2015
Dennis Ritchie
Mar 11, 2015
Dennis Ritchie
Mar 11, 2015
FG
Mar 11, 2015
Dennis Ritchie
Mar 11, 2015
Dennis Ritchie
Mar 11, 2015
FG
Mar 11, 2015
Ali Çehreli
March 11, 2015
Hi.
How to rewrite this in D to the handler method for the input parameter was determined on average in O(1)?

#include <string>
#include <iostream>
#include <functional>
#include <unordered_map>

class A
{
public:
    void foo(const std::string &s);

protected:
    void foo1(const std::string &s);
    void foo2(const std::string &s);
    void foo3(const std::string &s);

    std::string m_buf;
};

int main()
{
    A a;
    a.foo("first");
    a.foo("second");
    a.foo("third");
}

void A::foo(const std::string &s)
{
    using func = std::function < void(A &, const std::string &) >;
    static const std::unordered_map<std::string, func> handlers =
    {
        { "first",  std::mem_fn(&A::foo1) },
        { "second", std::mem_fn(&A::foo2) },
        { "third",  std::mem_fn(&A::foo3) }
    };

    const auto cit = handlers.find(s);
    if (cit != handlers.cend())
        cit->second(*this, s);

    m_buf += s + ' ';
}

void A::foo1(const std::string &s)
{
    std::cout << s << std::endl;    // prints first
}

void A::foo2(const std::string &s)
{
    std::cout << std::string(s.rbegin(), s.rend()) << std::endl;    // prints dnoces
}

void A::foo3(const std::string &s)
{
    std::cout << s << ", " << m_buf << std::endl;    // prints third, first second
}
March 11, 2015
A hash table? See http://dlang.org/hash-map.html
March 11, 2015
On Wednesday, 11 March 2015 at 16:08:22 UTC, Kagamin wrote:
> A hash table? See http://dlang.org/hash-map.html
 	
That is, the input is a string and, depending on what word it contains, is called one of the three methods of the class that this line handles. And this happens in average constant time (for hash). An associative array where the key is a string and value is a function.
March 11, 2015
The same without classes in Lisp:

(define (foo)
  (let ((foo1 (lambda (s) s))
        (foo2 (lambda (s) (list->string (reverse (string->list s)))))
        (foo3 (lambda (s) (string-append s ", " s " "))))
    (lambda (in)
      (match in
        ("first" foo1)
        ("second" foo2)
        ("third" foo3)
        (_ void)))))

(define (main)
  (define bar (foo))

  (for/list ([i '("first" "second" "third")])
    ((bar i) "poor c++")))
March 11, 2015
On 03/11/2015 07:33 AM, Dennis Ritchie wrote:

> How to rewrite this in D to the handler method for the input parameter
> was determined on average in O(1)?

D's associative arrays are hash tables.

The following program is as similar to the C++ one as possible:

import std.stdio;
import std.range;

class A
{
public:
    alias Func = void delegate(A, string);
    static const Func[string] handlers;

    static this()
    {
        handlers = [ "first" : (A a, string b) => a.foo1(b),
                     "second" : (A a, string b) => a.foo2(b),
                     "third" : (A a, string b) => a.foo3(b) ];
    }

    void foo(string s)
    {
        const handler = s in handlers;
        if (handler) {
            (*handler)(this, s);
        }

        m_buf ~= s ~ ' ';
    }

protected:
    void foo1(string s)
    {
        writeln(s);
    }

    void foo2(string s)
    {
        writeln(s.retro);
    }

    void foo3(string s)
    {
        writefln("%s, %s", s, m_buf);
    }

    string m_buf;
}

void main()
{
    auto a = new A();
    a.foo("first");
    a.foo("second");
    a.foo("third");
}

Ali

March 11, 2015
On 2015-03-11 at 17:42, Dennis Ritchie wrote:
> On Wednesday, 11 March 2015 at 16:08:22 UTC, Kagamin wrote:
>> A hash table? See http://dlang.org/hash-map.html
>
> That is, the input is a string and, depending on what word it contains, is called one of the three methods of the class that this line handles. And this happens in average constant time (for hash). An associative array where the key is a string and value is a function.

Yeah, lookup in D's associative arrays is generally O(1).
Here's the D version of your C++ code. A bit modified, to be more practical,
i.e. you can register hooks yourself and not have them hard-coded into the class.



import std.stdio, std.range;

class A
{
    alias Hook = void function(ref A, string);
    string m_buf;
    Hook[string] handlers;
    void foo(string s) {
        if (auto p = s in handlers)
            (*p)(this, s);
        m_buf ~= s ~ " ";
    }
    void register(string name, Hook hook) {
        handlers[name] = hook;
    }
}

void foo1(ref A a, string s) { writeln(s); }
void foo2(ref A a, string s) { writeln(s.retro); }
void foo3(ref A a, string s) { writeln(s, ", ", a.m_buf); }

void main() {
    A a = new A;
    a.register("first", &foo1);
    a.register("second", &foo2);
    a.register("third", &foo3);
    a.foo("first");
    a.foo("second");
    a.foo("third");
}
March 11, 2015
On 2015-03-11 at 18:27, Dennis Ritchie wrote:
> The same without classes in Lisp:
> [...]

And your point was...?  I take it, "poor c++" is a hint.
Don't compare apples to oranges.
March 11, 2015
Thank you very much, Ali Çehreli and FG.
March 11, 2015
On Wednesday, 11 March 2015 at 18:10:55 UTC, FG wrote:
> And your point was...?  I take it, "poor c++" is a hint.
> Don't compare apples to oranges.

No, I forgot to remove from the foreign code.