过程与函数 ( 积分: 50 )

  • 主题发起人 主题发起人 listhano
  • 开始时间 开始时间
Chrome: Object Pascal 的一个变种, 简洁多了
  Chrome是RemObjects推出的下一代Object Pascal语言,运行于.NET和Mono平台之上。在保留Object Pascal特性的同时,Chrome还借鉴了C#、Java、Eiffel等语言的优秀元素。

一种新的的语言诞生了:

C++ & Java -> C#

Object Pascal -> Chrome

namespace Chrome.Samples.SampleClasses;

interface

uses
System,
System.Collections;

type
SexEnum = (sxMale, sxFemale);

Person = class
private
fNickName: string;

protected
method SetNickName(Value : string);

public
constructor (aName : string; anAge : integer; aSex : SexEnum); virtual;

method GenerateSSN : string;

{ Notice how Chrome doesn't require the declaration of private fields to
store property values, thus making the code more compact and easier to read }
property Name : string;
property Age : integer;
property Sex : SexEnum;
property NickName : string read fNickName write SetNickName;
property Address : PersonAddress := new PersonAddress();

public invariants
{ These conditions are guaranteed to always be respected at the end of
the execution of a non-private method of the Person class }
Age >= 0;
Name <> '';
end;

PersonClass = class of Person;

PersonAddress = class
public
property City : string;
property Street : string;
property Zip : string;
end;

Employee = class(Person)
private
protected
method GetCurrency : double;

public
property Salary : double read GetCurrency;
end;

PersonCollection = class(CollectionBase)
private
protected
{ Type checking events }
procedure OnInsert(Index : integer; Value : Object); override;
procedure OnValidate(Value : Object); override;

{ Other methods }
function GetPersonsByIndex(anIndex : integer) : Person;
function GetPersonsByName(aName : string) : Person;

public
constructor;

method Add(aName : string; anAge : integer; aSex : SexEnum) : Person;
method Add(aPerson : Person) : integer;

method IndexOf(aPerson : Person) : integer;

procedure Remove(aPerson : Person);

{ Notice the use of overloaded array properties }
property Persons[anIndex : integer] : Person read GetPersonsByIndex; default;
property Persons[aName : string] : Person read GetPersonsByName; default;
end;

{ ECustomException }
ECustomException = class(Exception);

implementation

{ Person }

constructor Person(aName : string; anAge : integer; aSex : SexEnum);
begin
inherited Create;

Name := aName;
Age := anAge;
Sex := aSex;
end;

method Person.GenerateSSN: string;
var
lHashValue: integer;
begin
{ Generates a complex string with all the information we have and outputs a fake SSN
using the String.Format method }

lHashValue := (Age.ToString+'S'+Sex.ToString[2]+Name.GetHashCode.ToString).GetHashCode;
if lHashValue < 0 then lHashValue := -lHashValue;

result := String.Format('{0:000-00-0000}', lHashValue);
end;

method Person.SetNickName(Value : string);
require
Value <> '';
begin
fNickName := Value;
ensure
fNickName <> '';
end;

{ PersonCollection }

constructor PersonCollection;
begin
inherited;
end;

method PersonCollection.Add(aName : string; anAge : integer; aSex : SexEnum) : Person;
begin
result := new Person(aName, anAge, aSex);
List.Add(result);
end;

method PersonCollection.Add(aPerson : Person) : integer;
begin
result := List.Add(aPerson);
end;

method PersonCollection.IndexOf(aPerson : Person) : integer;
begin
result := List.IndexOf(aPerson);
end;

procedure PersonCollection.Remove(aPerson : Person);
begin
List.Remove(aPerson);
end;

function PersonCollection.GetPersonsByIndex(anIndex : integer) : Person;
begin
result := List[anIndex] as Person;
end;

function PersonCollection.GetPersonsByName(aName : string) : Person;
begin
for each somebody : Person in List do
if (String.Compare(aName, somebody.Name, TRUE)=0)
then Exit(somebody);
end;

procedure PersonCollection.OnInsert(Index : integer; Value : Object);
begin
OnValidate(Value);
end;

procedure PersonCollection.OnValidate(Value : Object);
begin
{ Notice the use of the "is not" syntax }
if (Value is not Person)
then raise new Exception('Not a Person');
end;

{ Employee }

method Employee.GetCurrency : double;
begin
case Age of
0..15 : Exit(0);
16..24 : Exit(15000);
25..45 : Exit(55000);
else exit(75000);
end;
end;

end.


CH03 - Generics in Chrome (Last updated 4/14/2005)

As part of our support for the upcoming Microsoft .NET Framework 2.0 (code-named Whidbey), Chrome provides full support for using and implementing the so called Generic Types.

What are Generics?

Generic types allow you to write strongly typed code that can later be used on a variety of different types. The classical example for efficient use of generics is container classes. Traditional class libraries (including the .NET Framework 1.1) usually implement containers by using a lowest common denominator class - for example System.Object. All the containers accept objects and will return objects and if you need lists of specific types (say, a custom class Foo), you will end up casting the elements obtained from your list, at runtime, as in this (contrived) example:


method Test;
var
lList: ArrayList := new ArrayList;
begin
lList.Add(new Foo);
lList.Add(5); // oops
//...
(lList[1] as Foo).Bar;
end;


Note how when accessing the element in the list, you need to cast the result back to a Foo manually before you can call its method. If for some reason a wrong type was added to the list (like the "5" that's added in the second line of code above). Your code will break with an invalid cast exception at runtime.

Instead, Generics allow you to write collections that are strongly typed to any given type. If ArrayList were a generic class, the code would look as follows and prevent any chance of type conflicts:


method GenericTest;
var
lList: ArrayList<Foo> := new ArrayList<Foo>;
begin
lList.Add(new Foo);
//lList.Add(5); // this will not compile
//...
lList[1].Bar; // no cast necessary, List[] is strongly typed
end;


The above example already shows you how to make use of existing generic classes from your Chrome code by using the new <> syntax to specify the concrete types (in this case Foo) with which you want to instantiate your generic class. The 2.0 Framework provides a wealth of reusable generic collections in the System.Collections.Generic namespace.

However, in addition to simply consuming existing classes, you can also use Chrome to implement your own generic classes, thus enabling users of your library to use them in a type-safe manner.

Implementing Generic Classes

As an example, let's implement a simple linked list as a generic class and look at the individual language features that are involved in making this work.


type
List<T> = public class
public
constructor(aData: T);
constructor(aData: T; aNext: List<T>);

property Next: List<T>;
property Data: T;

method ToString: string; override;
end;


The above class declaration defines a typical node for a linked list; the node contains two properties (the data for the actual node and a link to the next node in the list). It also contains a couple of helper functions which we will implement later to perform common actions on the list.

Generic Parameters

The first thing that will strike you immediately as different from a "normal" class declaration is the use of "T" in several places, for example as the type for the Data property. What is this T? How is it related to the actual types we want to store in our list?

Simply put, T is a so called Generic Parameter of your list class and acts as a placeholder for the actual concrete types with which your list will later be instantiated. If your user eventually instantiates a List<Int32>, then all occurrences of T will represent an integer value; if he instantiates a List<Foo>, they will represent Foos.

Generic Parameters are defined in the first line of your class declaration (List<T> = public class) and can then be used thoughout your class declaration and implementation in any place where a type is expected - as method parameters or results, as property of field types, or in code that deals with types.

Even though this example only declares one generic parameter (T), you can write classes that declare as many parameters as needed and you can use any valid identifier as parameter names (although a common convention is to use uppercase letters starting with "T").


type
Dictionary<Key, Value> = public class ... end;


is a perfectly valid generic class.

Let's implement the ToString method and see how we can work with the Data and Next properties, just as if they were real concrete types:


method List<T>.ToString: string;
begin
result := Data.ToString;
if assigned(Next) then
result := result +';'+Next.ToString;
end;


Note how each node will simply call the ToString method on Data and then defer to the next node's ToString to build the rest of the result; eventually building a complete list of all values by passing over each and every item of the list.

Calling ToString is possible because it is a member of Object and thus available for any possible type T. But what if we need to call more advanced members on the generic elements in our List? That's where Generic Constraints come into play.

Generic Constraints

Chrome allows you to limit the types that will be eligible for a given generic parameter. Limiting the types for T allows your code to make certain assumptions about T and, as a result, perform certain actions on the types that would not be valid on "any" type.

Two types of constraints are available for the 20 framework, Constructor Constraints and Type Constraints.

The first constraint allows you to require the concrete types used to instantiate your generic class to provide a constructor that is without any parameters. This is necessary if, for whatever reasons, you need to call the constructor and create new instances of T in your class. Take for example the following addition to our List<T> class:


method List<T>.AddNew: T;
var
lEnd: List<T>;
begin
lEnd := self;
while assigned(lEnd.Next) do
lEnd := lEnd.Next;

lEnd.Next := new List<T>;
lEnd.Next.Data := new T;
end;


Note how the last line of code creates a new instance of T and stores it at the end of the list. This is only possible if we can rely on T having a simple constructor without parameters, so we need to specify the Constructor Constraint for our generic class, using the "T has constructor" statement in the generic's where clause:


type
List<T> = public class
where T has constructor;
public
//...
end;


Secondly, lets assume that you want to add a Sort method to your list, which will use your favorite sort algorithm (say, Random Sort) to print the elements in your list into order. This presents us with a similar problem as before: to sort the list, we must be able to compare the individual items, but how can you compare the items without knowing their type? The answer is simple: let the individual items provide their own logic for comparing themselves via the IComparable interface and set a Type Constraint on your class to require that any concrete type used to instantiate your generic class must implement this interface.

This is done by supplying the "T is IComparable" statement in the where clause:


type
List<T> = public class
where T has constructor, T is IComparable;
public
//...
end;


The where clause

The where clause for a generic type can list any number of constraints, separated by commas. You can require several interfaces to be implemented by any given generic parameter, or you can require a specific ancestor class by specifying the said class. You can also mix requirements for several parameters, e.g.:


type
Dictionary<Key, Value> = public class ...
where Key is IComparable, Key has constructor, Value is Component;
// ...
end;


which defines a generic Dictionary class where the Key type must be comparable (understandably) & able to be created and the Value type must be Component or a descendant.

Summary

We hope this article has given you a quick introduction to what Generics are and how to use them in Chrome. The article only covered generic classes, but the concept of generics can also be applied to other language constructs, including methods, delegates and interfaces. Future articles and the Chrome Language Guide will provide you with more details on that.
 
觉不觉得这样做起来好像程序包装的更加严紧。
有些不用外界调用的东西都在过程里面了,也许有点好处吧。
 
to lich
你说的“Chrome”这个,是一种什么样的语言?容易使人接受吗?学习起来容易吗?
我想:一种语言是否能经受时间的考验,最主要的原因,是她的“实用性”;我很
想了解一下Chrome,那里能弄到教材?或者是简单的介绍也行!
 
我想这个Chrome语言可以看作是Pascal的一次浴火重生

脱胎换骨, 看上去似乎还兼容以前的语法

它还需要商业运作上的成功,只能靠M$这棵大树了,
不过将来,可能会支持Win32的开发

甚至,兼容VCL

http://www.remobjects.com/page.asp?id={C5B896C5-5C61-4C1C-A617-136711C07F46}

技术文档
http://www.chromesville.com/articles/?catid={5D67CCB4-B552-40C1-BE80-B8B623A89FB1}

可以集成到 VS.NET 2003
http://www.remobjects.com/trialdownloads.asp?id={57039A86-4B91-40CE-B1FA-A6170083C14C}
 
可以,完全可以
 
能够捉老鼠就是好猫
 
to dzl19

呵呵...精辟!
 
多看看delphi的源码,里面经常能看见这样的写法,个人认为,从安全性和效率上讲都很不错。
刚刚写代码就用到
procedure TfrmMain.cmbBCClick(Sender: TObject);
var
Year,Month,E:Integer;
function GetParamValue(s:String):String;
begin
s:=Trim(s);
if (s='all') or (s=GC_All) then
Result:='%'
else
Result:=s;
end;
begin
qryAttendanceList.Open;
Screen.Cursor:=crSQLWait;
qryAttendanceList.DisableControls;

if not TryStrToInt(cmbYears.Text,Year) then Year:=0;
if not TryStrToInt(cmbMonths.Text,Month) then Month:=0;
BuildDays(Year,Month);

qryAttendanceList.Parameters.ParamValues['sBCID']:=GetParamValue(cmbBC.Items.Names[cmbBC.ItemIndex]);
……………
……………
…………
 
呵呵,我也想听听
 
帮顶

--------签名档---------------------------

惊爆开源站

http://www.source520.com

80G源码电子书免费免注册下载,大量精辟技术文档库随时更新
 
后退
顶部