专利名称:反应式编程的编程语言支持的制作方法
技术领域:
本发明涉及计算机编程,尤其涉及反应式编程的编程语言支持。
背景技术:
数据处理是计算机编程的基本部分。可从各种编程语言中选择创建程序的编程语言。用于特定应用程序的所选语言可取决于应用程序上下文、开发者的偏好或公司政策等等。无论所选语言如何,开发者最终将必须处理数据,即查询和更新数据。数据可以根据其获得方式被归类为或是基于拉或是基于推。基于拉的数据是主动检取的数据。例如,程序可以在一阵列内的条目集合上迭代以请求和检取条目。类似地,可以从本地或远程数据库拉出数据。相反,基于推的数据在任意时刻被提供给程序。一个经典示例是响应于诸如鼠标移动或条目选择这样的用户输入来推出值的用户界面。鉴于通信等待时间、潜在误差或超时,异步计算也可以被视为基于推的数据的源。例如,程序可以请求在远程机器上执行计算,并且在计算完成时获得关于结果的通知。然而,返回计算结果的确切时间对于程序而言是未知的,并且会根据网络等待时间以及远程机器处理能力和负载等因素而变化。作用于基于拉的数据可被称为交互式编程,而作用于基于推的数据可被称为反应式编程。在交互式的基于拉的程序中,请求数据的程序代码受到控制,在继续执行之前,代码会在数据变得可用之前会一直等待或中断。或者,在反应式的基于推的程序中,环境(例如数据库、web服务、UI框架等)受到控制,并且确定数据何时被传送至应用程序。这里,程序代码不需要等待或中断。相反,代码可以继续执行并且在数据被异步地提供给它时做出适当反应。反应式编程(也叫作异步和/或基于事件的编程)在现代计算机应用中变得越来越普遍。特别是,在多核以及分布式或云计算的环境中,反应式编程是有利的。在这些情况下,例如,工作可以被分布在两个或更多核或计算机上。然而,反应式编程对于开发者来说会是繁重的。
发明内容
下面呈现了简化的发明内容,以便提供对所公开主题的某些方面的基本概念。本发明内容不是广泛性的概观。它并不旨在标识关键/重要元素,也不旨在划定所要求保护主题的范围。其唯一目的是以简化形式呈现一些概念,作为稍后呈现的更详细描述的序言。简言之,本发明一般涉及为反应式编程提供编程语言支持。库或类似的可重用组件可以提供代码,所述代码用于在程序本身外部的基于推的数据集合之上构成异步和基于事件的程序。向编程语言提供至少对这种库所提供的功能的一个子集的支持,以便于库的使用以及反应式编程。按照本发明一方面,可以为在包括事件、异步计算和属性在内的第一类和第二类模式之间的转换提供支持。按照本发明另一方面,可以提供支持以帮助产生和消耗基于推的数据,例如使用迭代程序。
为实现上述及相关目的,在此结合以下描述和附图描述了所要求保护主题的某些说明性方面。这些方面指示可实践本主题的各种方式,它们均落在所要求保护主题的范围之内。当结合附图阅读以下详细描述时,本发明的其他优点和新颖特征将变得显而易见。
图1是程序语言支持系统的框图。图2是代表性支持组件的框图。图3是代表性代码生成组件的框图。图4是便于反应式编程的方法的流程图。图5是将第二类模式转换成第一类模式的方法的流程图。图6是将第一类模式转换成第二类模式的方法的流程图。图7是便于创建和消耗基于推的数据的方法的流程图。图8是示出用于本发明各方面的合适操作环境的示意性框图。
具体实施例方式以下细节一般针对为反应式编程添加编程语言支持。反应式库或类似的可重用组件可以提供与异步和基于事件的编程(或者换言之,反应式编程)相关联的功能。换句话说,库可以为基于推的数据提供支持。更具体地,反应式库可以用第一类模式、实体等等(例如,IObservable、IftOperty等)来展示这种功能。常规的编程语言包括用于使用第二类模式、实体等的事件和异步编程的功能。对反应式编程的支持可以被集成在编程语言中,以帮助使用并相应地较少与例如反应式库相关联的学习曲线。特别是,可以在第一类模式和第二类模式之间发起转换。而且,例如基于迭代程序模式,可以提供程序语言支持来产生和消耗基于推的数据。现在参考附图更详细地描述本公开的各个方面,在全部附图中用相似的标记来指示相似或相应的元素。然而应该理解,附图及其相关详细描述不旨在将所要求保护的主题限于所公开的具体形式。相反,其意图是覆盖落在所要求保护主题的精神和范围之内的所有修改、等价物和替换的方案。首先参考图1,示出了程序支持系统100。系统包括程序组件110和反应式扩展组件120。程序组件110代表以特定编程语言指定的软件程序,该软件程序在被执行时就执行指定了的操作。例如,程序组件110可以是由开发者以高级编程语言(例如c# 、Visual Basic 等)创作的源代码。反应式库组件120可以和向程序组件110提供服务的可重用代码和数据的集合相对应。更具体地,通过在基于推的数据集合上展示第一类模式(例如IObservable、Property等),反应式库组件120可以被实现为便于异步以及基于事件或基于推的编程(或换言之,反应式编程)的软件库。尽管程序组件110可以支持反应性编程,它通常用第二类模式来表示,或者误用现有的语言特征来模仿期望的行为。因而,反应式库组件120可以对用于指定程序的程序语言的功能进行扩展,使其包括基于推的数据之上的第一类模式等等。第一类模式是用第一类对象或实体(例如程序语言概念)实现的设计模式(用于解决问题或计算问题的方案或框架)。换言之,第一类模式可以用程序性构造来实现,程序性构造可用于最大语言构造集合,一般因为将其视为对象对待。这使这一构造能作为参数被传递(例如,用于在第一类对象上定义诸如“运算符”这样的构造)、被作为结果返回、或者被分配给变量等等。换言之,第一类表示没有其他构造比第一类实体有更多能力。相反,第二类表示构造以某一方式受约束,例如使得实体不能作为参数被传递或被分配给一变量。程序支持系统100还包括支持组件130,该组件相对于反应式库组件120的使用而向程序组件110提供支持或帮助。例如,支持组件130至少可以发起将程序组件110的一个或多个第二类模式转换成反应式库组件120的一个或多个第一类模式。而且,例如,支持组件130可以以和基于拉的数据相同或类似的方式,提供能产生和消耗基于推的数据的功能。概而言之,支持组件130可以扩展编程语言,使用户更容易创作反应式程序,例如通过使用反应式库组件120。尽管不限于此,但是根据一个实施例,支持组件130所提供的功能可由编译器或类似组件来实现。图2描述了代表性的支持组件130。如图所示,支持组件可包括分析组件210和代码生成组件220。分析组件210可以分析程序,或更具体地说分析程序语法,以标识各种指定的模式和/或实体,这些指定的模式和/或实体诸如但不限于事件、异步计算和属性。代码生成组件220可以生成也称为支持代码的编程语言代码,所述编程语言代码至少引起或发起在第一类和第二类模式之间的转换,即,从第一类模式转换成第二类模式、或从第二类模式转换成第一类模式。另外或或者,代码生成组件220可以生成代码以便例如基于迭代程序模式来支持产生和消耗基于推的数据。图3是用于帮助澄清和理解本发明各方面的代表性代码生成组件220的框图。如图所示,代码生成组件220包括事件组件310、异步组件320、属性组件330、生产者组件340和消费者组件350。事件组件310生成代码以便至少发起到或自第一类事件模式的转换。许多编程语言具有事件的第二类表示。例如,事件可以如下定义public event EventHandler Click ;这一代码指令编译器生成以下代码(简化)//存储预订的专用后台字段,也用于激发事件private EventHandler Click;
public void add_Click(EventHandler value){
Click = Delegate.Combine(Click, value);
}
public void remove_Click(EventHandler value){
Click = Delegate.Remove(Click, value);
}而且,可以向已编译代码(例如,中间语言代码(IL))添加附加的元数据,使调用者知道此事件的可用性。事件可以从一个类中通过调用目前在后台字段中的委托来激发if (Click ! = null) Click. Invoke (ο, e);通过在事件上调用“+ =(添加事件)”或“_ =(移除事件)”,可以钩住或者解除预订事件,“+=(添加事件)”或“_=(移除事件)”又可以转变成前述的“添加”和移除方法。然而,事件不是第一类对象,而是第二类对象或第二类模式。结果,存在几个问题。首先,事件不能被单独传送。更具体地说,传送第二类事件的唯一方式是传送其包含的对象。而且,第二类事件不是合成的,例如,过滤器或投影不能写至其上、事件不能与其它事件联合、等等。此为,只有内部类才能激发该事件(例如,通过后台字段)。而且,只能返回值。不能发信号通知错误,因此没有完成的概念。还有,为了能脱钩事件,需要保存所添加的委托。图2的反应式库组件120可以使用户能在基于推的数据上指定第一类事件。例如public event IObservable<SomeType>Click ;这一代码可以指令编译器生成以下代码(简化)
//存储预订的专用后台字段,也用于激发事件
private Subject<SomeType> Click = new Subject<SomeType>();
public IObservable<SomeType> Click{
get { return click.AsObservable(); }
}为了预订该事件,用户可以写
6
var subscription = object. Click. Subscribe (...);为了稍后解除对该事件的预订,用户可以写subscription. Dispose ();为了激发事件,开发者可以在类中写Click. OnNext(value);为了通知错误,用户可以写Click. OnError (error);为了通知完成,开发者可以写Click. OnCompletedO ;而且,如果开发者想要使外部代码能激发事件,开发者可以写public event ISubject<SomeType>Click ;能改变公有属性的特征,使外部调用者能调用“ OnNext ”、“ OnError ”、或“OnCompleted”。当然,可以使用其它语法来指定第一类事件,第一类事件然后可被编译器转换成适当的调用(例如“+=”和“_=”)。第一类事件模式有许多好处。首先,第一类事件可以被传送。其次,事件是合成的。而且,开发者可以指定是否允许外部的人来激发事件。此外,发信号是更为昂贵的(例如,提供值、通知错误、通知已完成、等等)。还有,解除对事件的预订不需要保存或保留委托。常规的事件的程序表示和反应式库表示之间的差别清楚而繁多。事件组件310提供功能来桥接这些差别。特别是,有许多实现第二类事件的现有代码。因而,事件组件310可以帮助把这些事件带入反应式编程上下文。例如,假设按钮类具有一事件点击,如同
class Button{
public event EventHandler Click;
}为了将这一现有事件转换成第一类事件,事件组件310可以添加以下代码var click = Observable. FromEvent<EventHandler, EventArgs> (e = >newEventHandler (e),e = >button. Click+ = e,e = > button. Click- = e);click. Subscribe (…)因而,用户能够在公有事件上直接调用“预订”button. Click. Subscribe (...);当例如由图2的分析组件210检测到这种语法时,事件组件310可以自动地注入以上代码来支持第一类事件的使用。任选地,事件组件310可以对这一转换进行高速缓存,以避免转换若干次的开销。类似操作也可由事件组件310在相反方向上执行,S卩,从第一类事件到第二类事件。异步组件320可以生成代码以支持第一类异步计算或功能。更具体地,异步计算或功能的结果可成为第一类对象。程序可使用各种模式来执行包括Beginlnvoke/EndInvoke的异步计算。例如,考虑以下伪代码片断
var result = foo. BeginInvoke ( "a");var χ = foo. EndInvoke(result);注意到,首先需要调用结果Endlnvoke,再做其它。异步组件320可以生成代码以如下地转换到第一类对象var asyncFoo = Observable. FromAsyncPattern (string, int) (foo.Beginlnvoke,foo. Endlnvoke)这里,“var”是真正的 “Func (string 10bservable〈int>) ”。结果,用户可以使用asyncFoo作为第一类对象,诸如var result = asyncFoo ( “a,,);此外,因为反应式库组件120可允许返回错误以及值,因此通过异步计算转换到第一类实体有助于处理异常,等等。当然,根据需要,异步组件320也为相反方向上的转换提供支持,诸如从 “Func<string,I0bservable<int》”到 “BegirHnvoke/EncHnvoke,,。而且,可以添加程序语言支持。例如且不加限制,可以如下提供程序语言支持
Public bool IsEven(int value)
Func<int, IObservable<bool asyncIsEven = asyncof(IsEven);这里,关键词 “asyncof” 会触发生成对"Observable. FromAsyncPattern” 的正确调用。就像事件一样,大多数现代编程语言中的属性不是第一类。也就是,属性本身不能被传递。然而,包含属性的对象可以被传递。此外,外部代码不能容易地获悉对属性的改变。为避免这一点,开发者通常实现INotifyftOpertyChanged模式,其中开发者必须仔细地编
码每一个属性以便在改变时激发事件。下面是关于属性的这种现有模式的一个例子
class Customer: INotifyPropertyChanged{
public event PropertyChangedEventHandler PropertyChanged;private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}private string customerName ;
public string CustomerName {
get { return _customerName; }
set {
if (value !=—customerName) {
customerName = value; NotifyPropertyChanged("CustomerName");
private string _phoneNumber;
public string PhoneNumber {
get { return _phoneNumber; }
set {
if (value != _phoneNumber)
_phoneNumber = value; NotifyPropertyChanged("CustomerName");在反应式库的上下文中,例如,属性如下地被表示为第一类实体
权利要求
1.一种便于反应式编程的方法,包括采用被配置来执行存储在存储器(830)中的计算机可执行指令以执行以下动作的至少一个处理器(820)为程序生成使本机第二类模式被转换成在基于推的数据上操作的第一类模式的支持代码。
2.如权利要求1所述的方法,生成使第二类事件模式被转换成第一类事件模式的支持代码。
3.如权利要求1所述的方法,还包括在程序中标识指定第一类模式所支持的附加功能的语法。
4.如权利要求1所述的方法,生成使第二类异步模式被转换成具有第一类返回值的第一类模式的支持代码。
5.如权利要求1所述的方法,生成使第二类属性被转换成第一类属性的支持代码。
6.如权利要求1所述的方法,还包括生成使得产生基于推的数据的第一类模式的附加代码。
7.如权利要求1所述的方法,还包括生成使得用基于拉的数据模式来消费基于推的数据的附加代码。
8.如权利要求1所述的方法,还包括为程序生成使第一类模式被转换成第二类模式的附加支持代码。
9.一种程序语言支持系统,包括耦合到存储器(830)的处理器(820),所述处理器(820)被配置来执行存储在所述存储器(930)中的以下计算机可执行组件第一组件,其被配置成为程序提供支持代码,以便于利用一个库,该库提供支持异步的和基于推的计算的功能。
10.如权利要求9所述的系统,其特征在于,所述支持代码开始将第二类模式转换成第一类模式。
11.如权利要求10所述的系统,其特征在于,所述支持代码开始事件的转换。
12.如权利要求10所述的系统,其特征在于,所述支持代码开始异步模式的转换。
13.如权利要求10所述的系统,其特征在于,所述支持代码开始属性的转换。
14.如权利要求9所述的系统,其特征在于,所述支持代码开始将第一类模式转换成第二类模式。
15.如权利要求9所述的系统,其特征在于,所述支持代码在基于推的数据上编码迭代器模式。
全文摘要
本发明涉及反应式编程的编程语言支持。提供程序语言支持以便于反应式编程。提供了在第一类模式和第二类模式之间开始转换的代码,其中模式相对于基于推的数据来操作。还提供了对根据例如迭代器模式来产生和消费基于推的数据的支持。
文档编号G06F9/44GK102385513SQ20111030824
公开日2012年3月21日 申请日期2011年9月28日 优先权日2010年10月1日
发明者斯梅特 B·德, 费尔岑 D·范, H·J·M·梅杰, J·W·戴尔, 格格 J·范 申请人:微软公司