BASIC 并非已死!WIN32 亦然!是时候打破神话了。(第三部分)






4.40/5 (7投票s)
BASIC:一种常被低估和低估的强大语言
这是对另外两篇关于 BASIC 的文章的延续,但有所不同,加入了 WIN32。
我的故事简而言之,我是一名资深的 BASIC 程序员,从未后悔过。第一次接触 BASIC 是在 1975 年。经过这么多年的历程,解释为什么使用 BASIC,并揭露一些关于它的神话是很有意义的。第一个神话是,BASIC 是一种糟糕的语言,它作为解释语言的历史使其成为当今软件开发的不佳工具(这是错误的)。
BASIC 曾经而且一直是一种先进的语言。对此表示怀疑吗?当 Dartmouth 创建 BASIC 时,它在当时是一项奇迹。分时大型机(mainframe time sharing)的想法,让数百名学生可以同时在其上进行编码,这至少是令人震惊的。当时没有其他语言可以做到这一点。为什么选择 BASIC?易于编码和易于解释。你看,在运行时解释编程语言是一项非常困难的工作。你觉得你旧的 C 编译器很慢,需要很长时间才能编译一个应用程序(即“咖啡 break 综合征”),想象一下在运行时动态解释 BASIC 并产生体面的性能(当然,不如编译型语言快)。这不是一项容易完成的任务。然而,BASIC 允许学生实时编码(而不是为 FORTRAN 编写卡片,然后等待计算机部门几天后运行你的卡片批处理)。
20 世纪 80 年代迎来了家用计算机时代。还记得 Commodore 64、Atari 400/800、TI99/4A 等吗?Commodore 拥有 64 KB 内存和 1 MHz CPU。至少一半的内存地址分配给了 ROM,所以留给自己的程序空间不多了。想象一下,如果你不得不将 Windows 挤进其中。你甚至无法将 WIN32 的核心控制台 API 引擎(仅文本)挤进去。你甚至无法将 Windows 95 挤进去。然而,那些家用计算机让程序员能够编写代码并获得即时结果。你可能会惊讶于当时人们用 Commodore 64 做过什么。现在有些人可能会指出,当时 BASIC 是一种解释语言,而 C 这种真正的语言则是一个糟糕的替代品。神话 #2,BASIC 并非仅是解释型语言。在 80 年代,我使用 ABACUS BASIC 编译器将我的 BASIC 程序转换为纯机器语言,性能提升巨大。我甚至使用 ABACUS 编译器编写了自己的编译器(类似于 BASIC,包含 BASIC 的子集)。编译一个应用程序需要一些时间,但最终结果令人惊叹。此外,我还学习了 6502 机器语言,以便能够增强我的程序。
然后是 Windows 时代和 Visual BASIC。无论人们怎么说,Visual BASIC 改变了游戏规则。它引入了可视化设计到编程中,这在当时 C 甚至都不支持。难怪它如此受欢迎。现在,所谓的“公民程序员”(citizen programmer)出现了,那些工程师、技工或类似职业的人可以为他们的特定工作任务编写软件。他们实际上成为了比那些在大学里受过训练的“真正”程序员更好的软件开发者。为什么?
成为一名程序员并精通一门编程语言并不是成为一名优秀程序员的全部。如果你要为一家银行编写应用程序,程序员对银行业了解多少?如果你要为一名土木工程师编写应用程序,程序员对土木工程了解多少?一无所知!公民程序员是那些了解自己行业,同时又学会了用 BASIC 编程(一种公民可以理解的简单、自然的语言)的人,因此他们具有优势。他们比任何程序员都更了解自己的行业,所以他们经常编写出同行更欣赏的软件。这就是为什么 Visual Basic 会如此成功。诚然,所谓的“真正”程序员嘲笑它,但公民程序员编写应用程序的速度比 C 程序员喝几杯咖啡 break 的速度还快。
第一代 Visual BASIC 确实有一个弱点。它是一个 PCode 编译器,而不是原生代码(机器码)编译器。性能受到了影响。那些公民程序员会因为无知而坐视不管吗?不,他们要求越来越多。更好的功能,更好的性能。最终,微软意识到了这一点,并在后来的 Visual Basic 版本中加入了真正的原生代码编译器。Visual Basic 现在让 C 相形见绌。它成为了公民程序员的核心和灵魂。
Visual Basic 的问题在于,它并非从头开始设计成一门功能齐全的编程语言。微软购买了一款第三方开发的工具的版权(参见:https://en.wikipedia.org/wiki/Alan_Cooper),并将其塑造成 Visual Basic。它奏效了,并且取得了成功!但有一个缺陷。Visual Basic 并非从头开始设计,并且没有考虑到 WIN32 API 以及 Windows 在底层是如何工作的。它缺乏纯 C 的原始强大功能。
可视化设计在 Windows 世界中有其一席之地,但没有什么能取代纯粹的硬核编码。Visual Basic 占据了可视化设计市场,但在纯粹的硬核编码方面却有所欠缺。人们写了关于如何在 Visual Basic 中利用 WIN32 API 的书籍,但 WIN32 API 的学习曲线非常陡峭。即使是 C 程序员也感受到了挑战,微软也因此需要借助 MFC(Microsoft Foundation Classes)等工具来让他们生活更轻松,后来 C++ 也风靡一时。更糟糕的是,跨平台开发成为了软件开发的灵丹妙药,每个人都想开发 Web 应用。微软不得不寻找解决方案,.NET 应运而生,Visual Basic 的缓慢死亡也开始了。首先是 VB.NET 取代了 Visual Basic。随着时间的推移,C# 成为了 .NET 的首选,甚至 VB.NET 也处于缓慢的下滑螺旋中。
一些关键的教训随着时间的推移已经丢失。首先,BASIC 本身不是问题。.NET 狂潮的出现并非因为 Visual Basic 等语言的失败,而是源于对跨平台开发的需求。 跨平台开发虽然有效,但也因一个关键的错误前提而失败。认为完美的跨平台开发工具是万能的解决方法的想法是完全错误的。 为什么?因为要实现跨平台,就必须做出妥协,很简单。任何说不是这样的人都没有告诉你全部真相。GUI 框架,如 QT,是实现这一点的必要条件,因为不同的平台有不同的 GUI API,它们不能 100% 相互兼容。必须做出妥协,以便一个源代码可以编译到多个平台。这就是为什么有时你喜欢的应用程序看起来与其他平台上的应用程序不同。它们是为了让你使用的平台上的应用程序能正常工作而进行的“妥协”,但看起来并不完全是原生应用。跨平台设计是问题所在。是的,跨平台设计有其时间和地点。但也有一些时候,人们期望并偏好纯原生体验。 Windows 是当今最流行的桌面平台,因此编写利用该平台所有优势的应用程序是有意义的。
第二个教训是,在Windows 平台下,WIN32 API 是操作系统的核心,并将永远如此。近年来添加的所有花哨功能都只是建立在 WIN32 API 之上。如果你想在 Windows 上获得最佳性能,那么你越接近核心 WIN32 API,效果就越好。遗憾的是,当今的开发工具给人的印象是,一个人是伟大的程序员,因为他们可以即插即用各种预先编写好的库和组件。诚然,它们是必要的,但一旦你最喜欢的组件不再受支持,你的应用程序就陷入危机,因为你可能无法更新应用程序,因为组件的新版本不再可用。或者你想要超越该组件的功能,但它是一个固定的“黑盒子”,你无法修改它。你被锁定了。或者,对于你想要的任务,可能没有现成的库或组件可用,那么你将从何开始构建自己的呢?
好吧,你可以总是退一步学习纯 C(而不是 C++),然后使用 WIN32 API 从头开始编写组件。经典的 Visual Basic 程序员经常发现自己退回到 WIN32 API 并自己编写代码,这对我们今天来说是一个教训。计算机编程中一直存在对低级别控制的需求。那台老式的 Commodore 64 配备了一本手册,让你了解了计算机内部工作的全部知识。即使使用 BASIC,程序员也从未受到编程语言的限制。你可以在需要时添加机器码。甚至 BASIC 解释器也有低级别钩子,以便你可以扩展语言。有一家公司甚至突破了 Commodore 64 的极限,为它创建了一个功能齐全的 GUI,名为 GEOS(参见:https://en.wikipedia.org/wiki/GEOS_(8-bit_operating_system))。想象一下!在低端的 Commodore 64 上拥有类似 Windows 的体验。
回到 BASIC。BASIC 程序员真的能在 Windows 上编写出像纯 C 程序员那样的代码吗?答案是肯定的。现在 Windows 上有许多 BASIC 编程语言,例如
- Purebasic(付费软件,跨平台),非常受欢迎。 https://www.purebasic.com/
- Freebasic(免费) https://www.freebasic.net/
- ThinBasic(免费) https://www.thinbasic.com/
- Oxygen(免费,32 位和 64 位) https://github.com/Charles-Pegge/OxygenBasic
- Liberty Basic(付费) https://www.libertybasic.com/
- AutoIt https://www.autoitscript.com/site/autoit/
- Basic-256
- Basic for QT https://www.q7basic.org/
- BBC Basic https://www.bbcbasic.co.uk/bbcbasic.html
- Creative Basic https://www.ionicwind.com/cbasic.html
- GLBasic https://www.glbasic.com/
- True Basic(由 Basic 的原始创建者创建) https://www.truebasic.com/
- XBasic https://xbasic.sourceforge.net/
一些针对跨平台(尽管有妥协),一些针对 OpenGL,一些是解释型的,还有一些实际上允许你编写类似于纯 C 程序员使用 WIN32 API 的代码。我个人拥有 PureBasic、GLBasic 的许可证,并且玩过 Freebasic 和 ThinBasic。
还有更先进的 BASIC(或类似 BASIC)开发工具,它们提供更类似 Visual Basic 的体验,例如
- XOJO https://www.xojo.com/
- WINDEV https://windev.com/
- RADBASIC https://www.radbasic.dev/
- TWINBASIC https://twinbasic.com/
最后,我想提一下 Powerbasic,这也是我使用的。这样做的原因是因为,在我看来,Powerbasic 更接近老式的 C。它是最接近 WIN32 API 的语言。在我使用 WIN32 大约 20 年后,我可以证明,BASIC 编译器可以产生与 C 语言相同的性能和相同的原始强大功能。WIN32 API 并不容易学习,但值得去学习。无论你用什么语言编程,你都可以选择利用 WIN32 API 的原始强大功能。诚然,你可能需要语言选择中的 GUI 命令集来帮助更容易地工作。上面提到的每种 BASIC 都采取了不同的方法。但就原始功能和性能而言,使用的 GUI 框架越底层越好。这有区别吗?
根据我的经验,Powerbasic 最初没有 GUI 命令集,所以必须直接编写 WIN32 API 代码。虽然 Powerbasic 近年来在 WIN32 API 的对话框引擎之上添加了一个简单的包装器命令集,称为 DDT(动态对话框工具),许多人已经能够高效地使用它,但我在此之前就开始了,所以我需要构建自己的 GUI 框架来访问 WIN32 API。随着这个框架变得越来越强大,我一直坚持使用它。是的,提供一个比 WIN32 API 更容易使用的稍高层 GUI 命令集是有意义的,但这并不意味着应该完全屏蔽它,也不应该让框架过于笨重而显着降低性能。此外,这允许我在一台非常简陋的 PC 上进行开发,而不需要最新的 PC 硬件才能在不花费很长时间进行编译的情况下完成工作。那么你的开发 PC 看起来怎么样?最新的酷睿 I7(或 I9)?32 GB 内存?市场上最快的 SSD?
我目前的开发 PC 是一台我花了不到 100 美元买的旧翻新台式电脑。我将其从 Celeron CPU 升级到了 Intel Core2 Q8200 CPU,运行频率为 2.33 GHz,内存为 4 GB。硬盘是 145 GB,后来我添加了第二个 500 GB 硬盘。它运行的是最新版本的 Windows 10。虽然即使是旧版的 Visual Studio 加载起来也很慢,但我可以在几秒钟内启动 Powerbasic IDE,然后在大约 1 到 2 秒内编译我的 GUI 框架,该框架包含超过 50,000 行 WIN32 代码。Powerbasic 编译器是用汇编语言编写的,所以它快如闪电。结果才是最重要的,这正是 Powerbasic,以及使用 WIN32 API 作为 GUI 框架基础的地方真正闪耀。我的 GUI 框架(我称之为 EZGUI 5.0 Professional)只有大约 1 兆字节大小。是的,它可以放在一张老式软盘上。我的许多客户都在商业软件中使用它。(参见视频:https://www.youtube.com/watch?v=1rp2NtuxACg&t=272s,在大约 4 分钟 32 秒处暂停,注意笔记本电脑上运行的深水机器人。这个应用程序是我的客户使用我的 GUI 框架编写的)。GUI 框架拥有超过 1000 个 GUI 命令的命令集。今天的软件为什么会变得如此臃肿,真是可耻。Windows 为什么需要超过 2 GB 的内存,也是可耻的。
关键在于 WIN32 API 是一个令人惊叹的强大框架。它支持如此多的系统自定义,以至于你可以用它做任何事情。我使用 Ownerdraw、Customdraw、subclassing、superclassing、threads、DIB sections(设备无关位图)甚至 OpenGL(大多数 Windows PC 都提供访问)。我不仅可以访问内置的系统控件,还可以创建自己设计的全新控件。我创建了自定义控件,如文件列表框、属性列表框、MCI 控件、分割条控件、形状/热点控件、画布控件、OpenGL 画布控件等等。制作自己的 GUI 框架的一个挑战是如何构建一个可视化设计器。WIN32 API 没有内置的拖放引擎来构建表单设计器。所以,我设计了我自己的自定义拖动手柄控件和一个拥有可视化设计模式的 subclassing 引擎,以创建一个简单易用的拖放引擎。我完成这项工作最难的事情之一是如何绘制多个控件,甚至一次绘制数百个控件,并且能够平滑地绘制而不闪烁。同样,使用 WIN32,我能够构建自己的解决方案。
拖动手柄控件必须协同工作以定义一系列矩形,然后使用内存缓冲区在表单上绘制矩形(将它们视为一个图像)并平滑移动它们是一项挑战,但使用 WIN32 API 可以实现。
我早期学到的一个教训是,任何封闭的黑盒子库或组件都会有局限性。所以我为我的 GUI 框架添加了“钩子”,以便可以打开那个黑盒子并修改它的工作方式。我将钩子添加到核心消息循环、框架窗口过程等中。我提供了易于直接与 WIN32 交互的机制,这样你就不会陷入困境。即使是经典的 Visual Basic 也不能让你访问 WIN32 提供的所有内容(或者至少不容易)。有些事情很具挑战性,比如 subclassing 控件。我在 GUI 框架中内置了一个事件引擎,其中一个事件是 subclass 事件。你可以轻松地 subclass 任何控件(包括第三方控件),然后获取一个事件,其中每一个被处理的窗口消息都可以在你自己的事件例程中进行预处理。既然 WIN32 提供了对其自身引擎的钩子,为什么不在之上的 GUI 框架中也这样做呢。
教训很简单。BASIC 不是,也从未是问题。 BASIC 是一种先进的语言,多年来不断发展。我可以使用 Powerbasic 做几乎任何 C 语言能做的事情。我可以处理复杂的结构、指针、直接内存访问、线程等。我甚至可以使用内联汇编。此外,从头开始编写的 BASIC,类似于 C 并拥有所有高级功能,可以让你构建小型、快速的 Windows 应用程序。 使 BASIC 与 WIN32 API 协同工作并允许其进行低级别访问(API 函数、内存等),可以让你构建只有纯 C 才能比拟的应用程序。是的,你可以选择添加面向对象的编码风格。Powerbasic 提供这一点,但并非强制要求。你可以使用过程式设计或 OOP 设计来编写应用程序。选择权在于程序员。供你参考,WIN32 的核心并非面向对象。诚然,在其之上构建了一些 OOP,但核心 WIN32 是过程式设计的。这就是为什么非 OOP 的 WIN32 应用程序性能如此之好的原因。开销少得多。如果你想构建最快的 Windows 应用程序,那么过程式 WIN32 设计是最佳选择。
BASIC 不是一门死去的语言。新一代的 BASIC 层出不穷。 BASIC 的语法一直是吸引程序员(尤其是公民程序员)的因素。目前,我需要与一个客户合作(用 BASIC 编写应用程序),我需要检查项目中 C 语言编写的代码(用于微处理器固件)。虽然我无法编写 C,但我非常有能力阅读纯 C(过程式风格)。我用来学习 WIN32 API 编程的所有书籍都是为 C 程序员编写的,而不是为 BASIC 程序员编写的。经过多年对 C 的深入研究,我得出了同样的结论。为什么 C 语言如此简洁?为什么它没有更自然的语法。它无法与 BASIC 相提并论。一个简单的问题。为什么 C 语言还没有摆脱花括号?它们不能设计一种 C 语法,比如 BASIC、Python 那样,只使用换行符或回车符作为语法的一部分吗?我可能错了,但我的印象是,花括号是旧时代缓慢编译器的过时限制,当时编译一个应用程序需要数小时。在 25 MHz 的计算机上很难使编译器快速运行。花括号只是让编译器更容易,而不是程序员。有了当今如此强大的计算机,总会有人能够设计出不再需要花括号的 C 编译器。 我用 BASIC 编写的 WIN32 代码比同等的 C 代码更容易理解。此外,C 语言仍然停留在旧的以 null 结尾的字符串处理方法上。有些 BASIC 也是如此。定义一个跟踪字符串长度而不是强制使用 null 终止的字符串数据类型并不难。WIN32 已经拥有这个功能。在 C 语言中,它被称为 BSTR,但很少有程序员使用它,因为它似乎只在 COM 在 C 应用程序中使用。Powerbasic 编译器使用 BSTR 作为其主要字符串数据类型,而不是 null 终止(如果你需要,它也支持 null 终止,称之为 ASCIIZ)。Powerbasic 中的可变长度字符串是 BSTR(使用 WIN32 中的 OLE API),你甚至可以在其中嵌入真正的二进制数据,因为字符零是允许在字符串中的。在我看来,Powerbasic 拥有当今任何语言中最强大的字符串引擎。 那么为什么 BASIC 会提供比 C 更高级的机制呢(是的,C 支持 BSTR,但这并不是 C 的原生数据类型,而只是一个 WIN32 数据类型)。我可以用 Powerbasic 创建一个巨大的可变长度字符串,如下所示:
MSGBOX "start"
LOCAL MyVar AS STRING
MyVar = STRING$(1000000000, " ")
MSGBOX "length="+STR$(LEN(MyVar))
是的,一个长度为 10 亿个字符的简单字符串变量。我可以在其中存储任何我想要的二进制数据。它需要一两秒才能工作,但请记住,它是 1 GB。我甚至可以使用那个内存,并使用 DIM AT 命令和指针,在其中定义数组结构/数字。Powerbasic 甚至在字符串末尾添加了一个 null 终止符(不是字符串的一部分,而是它之后的一个字节),这样你就可以轻松地使用 STRPTR
函数,并将字符串传递给 WIN32 API,就像它是一个 null
终止的字符串一样(当然,字符串在此方式使用时不能包含零字符,但这正是 WIN32 所期望的,而不是 Powerbasic 的限制)。
是的,BASIC 编译器可以与 C 编译器媲美。特别是当它针对单个平台(如 Windows)时(C 编译器在针对不同平台时确实占有重要地位,但一些 BASIC 也可以类似地做到)。特别是在编写极小型、快速的应用程序时,BASIC 也能够胜任。
随时可以下载这个完全用 Powerbasic 编写的简单测试应用程序(我的 GUI 框架也完全用 Powerbasic 编写)。
使用 WIN32 编写的 GUI 框架演示测试应用: http://cwsof.com/download/testwin8.zip
这个示例应用程序演示了 Ownerdraw、Customdraw、2D 精灵动画、可视化设计引擎、OpenGL 3D 动画、复杂的窗口区域(非矩形窗体)、自定义控件和 MCI 等功能。整个应用程序只有 1.2 兆字节(可以放在软盘上)(不包括图形)。
结论是 BASIC 不是一门死去的语言,也不应该让它消亡。我今年已经 60 多岁了,我的编程生涯可能接近尾声,跟不上最新的新潮编程语言了,但我知道一件事。和许多其他 BASIC 程序员一样,我几十年来一直靠 BASIC 为生,并且将它推向了极限。 我的客户正在使用我开发的 GUI 框架,他们能够构建复杂的商业应用程序,这些应用程序被全世界使用,有些还在任务关键型环境中运行。如果我对编程界有一个期望,那就是重新审视 BASIC,看看它为什么能经受时间的考验。 尽管有大型科技公司提供的所有资源,但总会有人看到投入下一代 BASIC 的价值,而不是将其留给小型科技公司和独立开发者。C 程序员们,请尝试用纯 WIN32 API(或 MFC)来重现我上面的示例应用程序。其他程序员,请随意使用你使用的任何工具来重现该应用程序,但有一个限制,整个应用程序(不包括图形或媒体)的大小必须小于 2 兆字节,并且可以在从 Windows XP 到 Windows 11 的任何 Windows 版本上运行。
最后,请将信息发布给那些真正使用 BASIC 并靠它为生的人。不需要那些唱反调者、C 程序员之类的人发帖。我们 BASIC 程序员现在已经非常了解这个故事了。任何有价值的、多年来一直使用 BASIC 的 BASIC 程序员都清楚编程界对 BASIC 的看法。不必再重复了。