cosmos72 / cl-parametric-types

(BETA) C++-style templates for Common Lisp
45 stars 8 forks source link

Syntax for partial template specialization? #4

Closed cosmos72 closed 8 years ago

cosmos72 commented 8 years ago

I am open to suggestions :)

Given a general case like

(template (<t1> <t2>)
  (defstruct foo
    (bar nil :type <t1>)
    (baz nil :type <t2>)))

my idea for partial specialization syntax is something like:

(template (<t>)
  ;; applies if and only if <t1> and <t2> defined above
  ;; are BOTH equal to (array <t>) for some <t>
  (:specialized-for ((array <t>) (array <t>))
  (defstruct foo
    (bar nil :type (array <t>))
    (baz nil :type (array <t>))))

I also had a look at OPTIMA, but if I introduce general pattern matching, once there are multiple partial specializations for the same general template, I have no idea how to write the algorithm for deciding which one is the most specific (or to decide that none is more specific than the others)

Any thoughts? @guicho271828 ?

guicho271828 commented 8 years ago

Could you elaborate a bit more about the example? I think I'm not getting the idea well.

cosmos72 commented 8 years ago

Let me add the C++ equivalent, and see if it helps: the CL template

(template (<t1> <t2>)
  (defstruct pair
    (first  nil :type <t1>)
    (second nil :type <t2>)))

is equivalent to C++

template<class T1, class T2>
struct pair
{
  T1 first;
  T2 second;
};

Then in C++, a partial specialization for pair, for example when first and second are both std::vector<T> for some T, would be:

template<class T>
struct pair<std::vector<T>, std::vector<T> >
{
  std::vector<T> first;
  std::vector<T> second;
};

I proposed to represent such partial specialization with the syntax:

(template (<t>)
  (:specialized-for ((array <t>) (array <t>))
  (defstruct pair
    (first  nil :type (array <t>))
    (second nil :type (array <t>))))

Thinking about it, one alternative could be the syntax:

(template (<t>)
  (defstruct (pair (array <t>) (array <t>))
    ...))

it has one objective advantage: it is almost identical to C++. In my opinion it has a disadvantage too: the meaning of a single (template ...) containing multiple definitions is probably less clear

guicho271828 commented 8 years ago

I got it. (1) The first syntax looks better than the alternative syntax because the latter changes the defstruct syntax. Next, (2) The point "multiple definitions is probably less clear" is not obvious to me. I guess it would have to repeat the partial specialization, e.g.:

(template (<t>)
  (defstruct (pair (array <t>) (array <t>))
    ...)
  (defun (less (array <t>) (array <t>)) (a b)
    ...))

which is a disadvantage, but it could be refined by typedef equivalent (discussed later). Anyway, although (2) is not obvious to me, due to (1), I also vote for the first syntax.

Question: Are those arguments matched to the original parameters by the positions? For example, "will it blend" if you mix two templates with the different parameter names?

(template (<t1> <t2>)
  (defstruct pair1 ...))
(template (<t2> <t3>)
  (defstruct pair2 ...))
(template (<t>)
  (:specialized-for ((array <t>) (array <t>))
  (defstruct pair1 ...)
  (defstruct pair2 ...))

Re: typedefs. proposal:

(template (<t>)
  (:typedef <t1> (array <t>)) ;; this does not imply specialization --- just a local alias
  (:specialized-for (<t1> <t1>)
  (defstruct pair
    (first  nil :type <t1>)
    (second nil :type <t1>)))
cosmos72 commented 8 years ago

On Apr 30, 2016 3:51 AM, "Masataro Asai" notifications@github.com wrote:

I got it. (1) The first syntax looks better than the alternative syntax because it changes the defstruct syntax. Next, (2) The point "multiple definitions is probably less clear" is not obvious to me. I guess it would have to repeat the partial specialization, e.g.:

(template () (defstruct (pair (array ) (array )) ...) (defun (less (array ) (array )) (a b) ...))

which is a disadvantage, but it could be refined by typedef equivalent (discussed later). Anyway, although (2) is not obvious to me, due to (1), I also vote for the first syntax.

Ok, it makes sense. Thanks for the feedback

Question: Are those arguments matched to the original parameters by the positions? For example, "will it blend" if you mix two templates with the different parameter names?

(template ( ) (defstruct pair1 ...)) (template ( ) (defstruct pair2 ...)) (template () (:specialized-for ((array ) (array )) (defstruct pair1 ...) (defstruct pair2 ...))

Yes, parameters are matched by position

Re: typedefs. proposal:

(template () (:typedef (array )) ;; this does not imply specialization ;; just a local alias (:specialized-for ( ) (defstruct pair (first nil :type ) (second nil :type )))

I was thinking about local types too... CL has flet and macrolet, but no typelet. Not a big problem usually, because deftype is not used heavilly, but with templates requiring explicit types it would be very useful. No idea how to implement typelet in the most general case though... easy to do immediately inside (template... ), but what about outside it, or deep inside a template function?

Regards, Massimiliano

cosmos72 commented 8 years ago

Implemented syntax (1) i.e.

    (template (<t>)
      (:specialized-for ((array <t>) (array <t>))
      (defstruct pair
        (first  nil :type (array <t>))
        (second nil :type (array <t>))))