D如何处理Concept?

14 views
Skip to first unread message

longshanksmo

unread,
Sep 14, 2007, 7:17:58 PM9/14/07
to TopLanguage
D还不支持Concept。那它如何处理C++98中遇到的问题。是否有其他手段?
如果Concept仅仅提高出错的可读性,那也就罢了。
但Concept参与到特化时,促使整个模板系统具备更细的抽象粒度。可以处理任意的同一语义,但又不同实现的东西。

BTW:大概了解了一下D,很不错的语言。语法相比C++干净很多,基础很好。作为面向系统开发的语言,砍掉一部分不常用的特性是合理的举措。不过,一
旦成功,贪得无厌的程序员们,自然会尽其所能地将各自喜好的特性塞进语言,慢慢地又变成一个复杂的通用语言。
这种现象在C、Ada、C++,甚至现在的Java身上都发生过。一个混乱的世界。

oldrev

unread,
Sep 14, 2007, 11:20:55 PM9/14/07
to pon...@googlegroups.com
hi:

D独创的"二元关键字" static if 和 static assert,几乎实现 C++0x concept
的效果。


在 2007-09-14五的 16:17 -0700,longshanksmo写道:

red...@gmail.com

unread,
Sep 14, 2007, 11:40:04 PM9/14/07
to pon...@googlegroups.com
还有类的 invariant , 在里面可以测试类不变式是否还保持正确.

函数除了 body, 还可以写 in, out, 测试进入和退出条件.

oldrev 写道:

red...@gmail.com

unread,
Sep 14, 2007, 11:42:27 PM9/14/07
to pon...@googlegroups.com
我回答错了, 我答到 design by contract 那边去了.

说到出错信息, 到目前为止, 我碰到的D 的模板出错信息都是明确易读的.

oldrev 写道:

red...@gmail.com

unread,
Sep 14, 2007, 11:45:07 PM9/14/07
to pon...@googlegroups.com
不管怎么说, 起码 OO, GP 部分功能很强, 以后这部分不太可能变得非常杂乱.

现在 D2.0 的设计, 很多是为了 fp 和并发编程考虑的, 这些如果也设计好了, 起
码在这些重要的点上,
不会出现太混乱的情形.

longshanksmo

unread,
Sep 14, 2007, 11:58:27 PM9/14/07
to TopLanguage
那么Concept的特化作用呢?是否也有对等的机制?

oldrev

unread,
Sep 15, 2007, 12:31:42 AM9/15/07
to pon...@googlegroups.com
实现的办法很多,低效一点的用接口特化:

interface ICallable(Params...)
{
alias Params PT;
void opCall(Params args);
}

class Foo : ICallable!(int, int)
{
override void opCall(PT args)
{
}
}

当然了,这不是一个好例子,接口并不适合做模板,这里只是演示D有此能力。
更好的是使用模板值参数特化:

void func(T, bool checkConcept : true =
ArithmeticTypeConcept!(T))(T arg)
{
...
}

实际上D有更多的模式可供使用,已经实现的 D2.0Alpha 提供了静态反射
(__traits),配合 static assert 和 static if 可以更好地处理这些类型问
题。

在 2007-09-15六的 03:58 +0000,longshanksmo写道:

longshanksmo

unread,
Sep 15, 2007, 2:02:56 AM9/15/07
to TopLanguage

> 当然了,这不是一个好例子,接口并不适合做模板,这里只是演示D有此能力。
> 更好的是使用模板值参数特化:
>
> void func(T, bool checkConcept : true =
> ArithmeticTypeConcept!(T))(T arg)
> {
> ...
>
> }
> 当然了,这不是一个好例子,接口并不适合做模板,这里只是演示D有此能力。
> 更好的是使用模板值参数特化:
>
> void func(T, bool checkConcept : true =
> ArithmeticTypeConcept!(T))(T arg)
> {
> ...
>
> }
>

这是模板特化本身提供的static dispatch,可以算concept的模拟。形式上比C++更简洁,但本质是一样的。
concept提供了更"自然"和灵活的形式:
template<has_swap_mem T> //如果有swap成员,用swap成员交换
void swap(T& a, T& b)
{
a.swap(b);
}
template<has_exch_mem T>
requires !has_swap_mem<T>
void swap(T& a, T& b) //如果有exch成员,没有swap成员,用exch交换
{
a.exch(b);
}
template<typename T>
void swap(T& a, T& b) //其他的用临时变量交换
{
T t(a);
a=b;
b=t;
}
使用时,编译器根据T的特征寻找匹配的swap版本。
也可以使用concept_map,把拥有exch的类型"打扮"成has_swap_mem:
template<has_exch_mem T>
concept_map has_swap_mem<T> {
void swap(T& a, T& b) {
a.exch(b);
}
}
concept对于gp而言有非常重要的作用,否则,C++也不会在增加一个复杂的特性。concept对于D而言,差不多是现成的,C++已经指明了
方向。

oldrev

unread,
Sep 15, 2007, 2:43:42 AM9/15/07
to pon...@googlegroups.com
我没有发现这比D2.0的实现更清晰:

void swap(T)(ref T x, ref T y)
{
static if(__traits(hasMember, T, "swap")) {
x.swap(y);
}
else if(__traits(hasMember, T, "exch")) {
x.exch(y);
}
else {
T tmp = x;
x = y;
y = tmp;
}
}

参考:
http://www.digitalmars.com/d/traits.html

- Oldrev

在 2007-09-15六的 06:02 +0000,longshanksmo写道:

lijie

unread,
Sep 15, 2007, 2:54:52 AM9/15/07
to pon...@googlegroups.com
这个还是is表达式比较合适:


void swap(T)(ref T x, ref T y)
{
       static if(is(x.swap(y))) {
               x.swap(y);
       }
       else static if(is(x.exch(y))) {

               x.exch(y);
       }
       else {
               T tmp = x;
               x = y;
               y = tmp;
       }
}

在07-9-15,oldrev < old...@gmail.com> 写道:

lijie

unread,
Sep 15, 2007, 2:58:33 AM9/15/07
to pon...@googlegroups.com
虽说D的实现更容易,但concept更清晰,毕竟是定义在函数形式上的而不是实现代码里面。

在07-9-15,lijie <cpu...@gmail.com> 写道:

pongba

unread,
Sep 15, 2007, 3:14:08 AM9/15/07
to pon...@googlegroups.com
这个不是合适,是ad-hoc。C++一度也是这样的,见boost.concept_check

pongba

unread,
Sep 15, 2007, 3:19:03 AM9/15/07
to pon...@googlegroups.com
一个first-class的概念理应被first-class的表达。

这个不是合适,是ad-hoc。C++一度也是这样的,见boost.concept_check





--
刘未鹏(pongba)|C++的罗浮宫
http://blog.csdn.net/pongba
TopLanguage
http://groups.google.com/group/pongba

oldrev

unread,
Sep 15, 2007, 3:20:22 AM9/15/07
to pon...@googlegroups.com
static if是可以放在只能放声明的地方的,但是不知道为什么这样做的话会失去
自动类型推导的能力(a bug?):

import std.stdio;

template swap(T)


{
static if(__traits(hasMember, T, "swap"))
{

void swap(ref T x, ref T y) {
x.swap(y);
}
}
else static if(__traits(hasMember, T, "exch"))
{
void swap(ref T x, ref T y) {
x.exch(y);
}
}
else
{
void swap(ref T x, ref T y)

{
T tmp = x;
x = y;
y = tmp;
}
}
}

class Foo
{
void swap(Foo f)
{
writefln("Foo.swap");
}
}

class Bar
{
void exch(Bar b)
{
writefln("Bar.exch");
}
}


void main()
{
Foo f1 = new Foo;
Foo f2 = new Foo;

swap!(Foo)(f1, f2);

Bar b1 = new Bar;
Bar b2 = new Bar;

swap!(Bar)(b1, b2);

int x = 1, y = 2;
swap!(int)(x, y);
writefln("x=", x, ", y=", y);

}

- Oldrev

在 2007-09-15六的 14:58 +0800,lijie写道:
> 虽说D的实现更容易,但concept更清晰,毕竟是定义在函数形式上的而不是实

redsea

unread,
Sep 15, 2007, 3:26:04 AM9/15/07
to TopLanguage
这种方式不便扩展.

BTW: 说起 hasMember 这件事情, D2.0 里面一个 feature 和这个有交集, 不知道会如何处理.
D 2.0,

void func(int i){}

可以被当作 int 的 member 调用
int i;
i.func();

不知道在 traits 判断里面是否认为这个是 member ? (这个特性是为了容易扩展已经实现的类层次而设计的).

> > 方向。- Hide quoted text -
>
> - Show quoted text -

oldrev

unread,
Sep 15, 2007, 3:32:30 AM9/15/07
to pon...@googlegroups.com
这是不行的,自由函数当作成员函数调用目前仅限于数组,Walter 的幻灯片里提
到未来可能会为类和结构增加这个特性,这只是个语法糖,应该不能被算作成员函
数。

__traits(compiles) 能处理允许二者都合法的情况。

- Oldrev

在 2007-09-15六的 00:26 -0700,redsea写道:

pongba

unread,
Sep 15, 2007, 3:36:35 AM9/15/07
to pon...@googlegroups.com
自由函数当成成员函数调用的语法糖C#已经提供了,其实我觉得在C++这样的多范式语言里面最好不要这么做,会提供一种"面向对象"的假相,从而鼓励不必要的OO。

不过这个语法糖倒是有一个用处----对付遗留代码。

template<typename T>
void f(T t)
{
t.exec();
}

如果f不可修改,那么对于语法上没有成员函数exec但语义上有exec的类,可以写一个自由函数exec,然后被当作成员函数执行。

On 9/15/07, oldrev <old...@gmail.com> wrote:

lijie

unread,
Sep 15, 2007, 3:37:15 AM9/15/07
to pon...@googlegroups.com
D的模板函数参数推导很长一段时间都没有进展了,印象中有一年了吧。以前做的一个矩阵相乘自动推导维度的现在还编译不过:

class Matrix(T, int R, int C){ 
    static assert(R > 0 && C > 0); 
 
    Matrix!(T, R, C1) opMul(int C1)(Matrix!(T,C,C1) rhs){ 
        return null; 
    } 


调用时必须显式地指定这个C1参数,否则无法根据rhs参数自动推导出来,这个在C++中早就解决了的。

在07-9-15,oldrev < old...@gmail.com> 写道:

longshanksmo

unread,
Sep 15, 2007, 4:07:27 AM9/15/07
to TopLanguage
On Sep 15, 2:43 pm, oldrev <old...@gmail.com> wrote:

清晰只是一方面。在concept下,swap的每一个实现都是独立的个体,这样也就突出了各种版本的独立性和特有性,对于代码的理解有所帮助。但这只
是一种心理上的"安慰"。更重要的是:
当我需要增加一种swap的实现,static if是否可行?是否意味着需要D允许合并两个不同函数或类的scope?
concept促使我们按照这样一个逻辑写模板:首先说明我这个模板是针对什么样的类型的。然后,再具体阐述这个模板的内容。对于函数模板而言,这更接
近算法理论的逻辑。
另外,就像pangba说的,first class的概念需要first class机制实现。concept和concept-map是
first class的机制,结果就是,first-class的机制往往是"多功能的"(我喜欢说"更接近于'道'"。:))。比
如,concept可以消除或简化一些traits的使用:
我首先利用concept和concept-map定义Integers和Floats分别代表整数和浮点数两个concept:
concept Integers<typename T>{...}
concept Floats<typename T>{...}
concept_map Integers<int>{};
concept_map Integers<long>{};
...
concept_map Floats<double>{};
concept_map Floats<float>{};
...
然后,我就可以使用了:
template<Integers T> T fun(T a, T b) {...}
template<Floats T> T fun(T a, T b) {...}
这些traits concept一次定义永远使用。(C++0x的标准库应该有这些东西,我没注意过)。
而我前一次回复中利用concept_map制作concept适配器,似乎还是没有办法替代的。

oldrev

unread,
Sep 15, 2007, 4:48:18 AM9/15/07
to pon...@googlegroups.com
看来我对 C++ 的 concept 了解的还是不够。

D 应该能模拟实现 concept 的所有功能,但是像 Pongba 说的,这不是 first-class,目前只能说是 "Not so pretty, but it works.",就跟 boost.concept_check 库差不多。

D 是社区驱动加仁慈专制的开发方式,如果真的有需要的话D也很快能实现这个东西,至少是在 C++0x 之前。

其实这个问题应该去问 Andrei Alexandrescu,呵呵

在 2007-09-15六的 08:07 +0000,longshanksmo写道:

longshanksmo

unread,
Sep 15, 2007, 8:33:57 AM9/15/07
to TopLanguage
相信D将来会实现concept的,毕竟是使用的好东西嘛。期待中。

Atry

unread,
Sep 15, 2007, 8:36:45 AM9/15/07
to pon...@googlegroups.com
我觉得 D 不会实现 concept 的,因为 concept 没有一个二进制接口,是不能根据 concept 来连接的。concept 的唯一重用方式就是 C++ 的头文件,而那正是 D 所批判的东西。

在07-9-15,longshanksmo < m...@seaskysh.com> 写道:

red...@gmail.com

unread,
Sep 15, 2007, 8:55:48 AM9/15/07
to pon...@googlegroups.com
D 一样是通过 "头" 文件来共享信息的, 只是这个头文件,

1. 用 import, 不是 include
2. import 的时候, 是整个符号表引入, 不是重新进行词法语法分析

因此, 不会和实现 concept 有冲突.

Atry 写道:

Reply all
Reply to author
Forward
0 new messages