Как построить обобщённый тип с ограничениями?
От: SergASh  
Дата: 26.08.07 13:55
Оценка:
Приве всем!

Пытаюсь построить generic-тип с произвольным количеством параметров. В метод передаётся сколько должно быть типов по значению и сколько по ссылке.
Вопрос в том, как сгенерировать ограничения where для заранее неизвестного количества типов.
public BuildKeyClass( byRefCount : int, byValCount : int ) : void
{
  def refTypeNames = $[$"U$i" | i in $[1..byRefCount]];
  def valTypeNames = $[$"V$i" | i in $[1..byValCount]];
  def typeNames = refTypeNames.Append( valTypeNames );
  def types = typeNames.Map(id => <[ $(id : usesite) ]>);
  def typeParams = types.Map( n => { | <[$(n : name)]> => PT.Splicable.Name( n ) } );

  /*
  def getHead( _ )
  {
    | head :: _ => head;
  }
  def tp = getHead( typeParams ); // Так можно получить только заранее известное количество типов
  */
  
  def env = workingContext_s.Env;
  def builder = env.Define( 
    <[decl:
      public class $(className : dyn) [..$typeParams]
  //    where $tp : struct // Это работает, но только для заранее известного количества типов
      {
      } 
    ]> );    
  builder.Compile(); 
}

Хочется получить в выделенной жирным строке что-то вроде
  where U1 : struct
  where U2 : struct
  where U3 : struct
  where V1 : class
  where V2 : class

Как это сделать?

Спасибо.
Re: Как построить обобщённый тип с ограничениями?
От: SergASh  
Дата: 27.08.07 11:53
Оценка:
Пока удалось только полухаком через AST. Может кто знает как это псевдоцитированием заменить?
public BuildKeyClass( byRefCount : int, byValCount : int, byRefAuto : int = 0, byValAuto : int = 0 ) : TypeBuilder
{
  def buildName = seed => $"$(seed)_R$(byRefCount)A$(byRefAuto)V$(byValCount)A$(byValAuto)";
  def className : string = buildName( "Key" );

  def makeName = str => <[ $(str : usesite) ]>;
  def makeTypeParams = _.Map( n => { | <[$(n : name)]> => PT.Splicable.Name( n ) } );
  def makeConstraints = ( lst, name ) => lst.Map( PT.Constraint( _, makeName( name ) ) );

  def refTypeNames = $[$"U$i" | i in $[1..byRefCount]];
  def valTypeNames = $[$"V$i" | i in $[1..byValCount]];
  def refTypes = refTypeNames.Map( makeName );
  def valTypes = valTypeNames.Map( makeName );

  // Generic class stuff
  def refTypeParams = makeTypeParams( refTypes );
  def valTypeParams = makeTypeParams( valTypes );
  def refConstraints = makeConstraints( refTypeParams, "class" );
  def valConstraints = makeConstraints( valTypeParams, "struct" );
  def typeParams = refTypeParams + valTypeParams;
  def constraints = refConstraints + valConstraints;
  def root = <[decl:
               public class $(className : usesite) // [..$typeParams ] // It's not necessary any more.           
               {
               } 
             ]>;      
  root.td.typarms = PT.Typarms( typeParams, constraints );

  // Declare class skeleton
  def env = workingContext_s.Env;
  def builder = env.Define( root );            
  def defineMembers = _.Iter( f => builder.Define( f ) );

  // Declare fields
  def refFieldNames = $[1..byRefCount].Map( i => $"key$(i)_" );
  def valFieldNames = $[1..byValCount].Map( i => $"key$(i + byRefCount)_" );

  def refFields = List.Combine( refTypes, refFieldNames ).Map(
    ( typ, fld ) => <[ decl: private mutable $(fld : usesite) : $typ = null; ]> );
  def valFields = List.Combine( valTypes, valFieldNames ).Map(
    ( typ, fld ) => <[ decl: private mutable $(fld : usesite) : $typ ]> );

  defineMembers( refFields );
  defineMembers( valFields );

  // Declare properties
  def refPropNames = $[1..byRefCount].Map( i => $"Key$(i)" );
  def valPropNames = $[1..byValCount].Map( i => $"Key$(i + byRefCount)" );

  def refProps = List.Combine( refTypes, List.Combine( refFieldNames, refPropNames ) ).Map(
                 fun( _ ) 
                 { | ( typ, ( fld, prop ) ) => 
                      <[decl: 
                        public $(prop : usesite) : $typ 
                        { 
                          get 
                          { 
                            $(fld : usesite); 
                          } 
                          set 
                          { 
                            $(fld : usesite) = value; 
                          } 
                        } 
                      ]> 
                 } );
  def valProps = List.Combine( valTypes, List.Combine( valFieldNames, valPropNames ) ).Map(
                 fun( _ ) 
                 { | ( typ, ( fld, prop ) ) => 
                      <[decl: 
                        public $(prop : usesite) : $typ 
                        { 
                          get 
                          { 
                            $(fld : usesite); 
                          } 
                          set 
                          { 
                            $(fld : usesite) = value; 
                          } 
                        } 
                      ]> 
                 } );

  defineMembers( refProps );
  defineMembers( valProps );

  builder.Compile();
  builder;
}
Re: Как построить обобщённый тип с ограничениями?
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.08.07 11:56
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>Пытаюсь построить generic-тип с произвольным количеством параметров. В метод передаётся сколько должно быть типов по значению и сколько по ссылке.

SAS>Вопрос в том, как сгенерировать ограничения where для заранее неизвестного количества типов.
SAS>
SAS>    <[decl:
SAS>      public class $(className : dyn) [..$typeParams]
SAS>  //    where $tp : struct // Это работает, но только для заранее известного количества типов
SAS>

SAS>Хочется получить в выделенной жирным строке что-то вроде
SAS>
SAS>  where U1 : struct
SAS>  where U2 : struct
SAS>  where U3 : struct
SAS>  where V1 : class
SAS>  where V2 : class
SAS>

SAS>Как это сделать?

Думаю, так:
  ...
  def builder = env.Define( 
    <[decl:
      public class $(className : dyn) where ..$constraints
  ...


Естественно в constraints должны быть список специально подготовленных для констрэйнов.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Как построить обобщённый тип с ограничениями?
От: SergASh  
Дата: 27.08.07 12:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Думаю, так:

VD> ...
VD>Естественно в constraints должны быть список специально подготовленных для констрэйнов.

Спасибо, это конечно лучше, чем TopDeclaration.typarams перезаписывать. Интересно как это работает, ведь для каждого типа нужно отдельно писать where, а здесь оно только раз указано и не входит в цикл.

А сами ограничения псевдоцитированием можно построить, или только явно через Parsetree.Constraint ?
Re[3]: Как построить обобщённый тип с ограничениями?
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.08.07 11:54
Оценка:
Здравствуйте, SergASh, Вы писали:

SAS>А сами ограничения псевдоцитированием можно построить, или только явно через Parsetree.Constraint ?


Я это не выяснял. Скорее всего органичения исходно записываются в виде выражения, а это значит, что можно. Но не факт.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.