在 GNU Smalltalk 中导入文件
Importing files in GNU Smalltalk
我是 GNU Smalltalk 的新手。我知道在大多数编程语言中,有一个 import
/#include
/require
命令可以让一个源文件访问另一个源文件的内容。我的问题是,如何在 GNU Smalltalk 中将一个文件导入另一个文件?任何帮助,将不胜感激。谢谢!
它可能在没有 import/include/require/use 的情况下工作,因为 Smalltalk 是后期绑定的:
- class 名称在传统名称为 Smalltalk 的全局命名空间中解析,它是(曾经)将 class 名称(键)关联到 class(值)的 SystemDictionary。这个键值对是一个绑定或关联对象,具体取决于 Smalltalk 品牌。编译器生成的字节码只是推送存储在已编译方法文字中的绑定(理解为指针,绑定是共享的),并提取它的值。
- 如果 class 还不存在,则绑定将存储到名为 Undeclared 的特殊字典中。如果以后定义了这个未声明的变量,那么定义就会改变(即值改变),绑定移动到系统字典。
- 至于方法名称(所谓的选择器),它们直到运行时才完全解析:编译器生成的字节码是:推送接收器。推动论点。发送选择器。
启用后期绑定的原因是您只能通过发送消息与对象进行交互。消息查找是在运行时通过在接收方的 class methodDictionary.
中搜索与选择器对应的键来执行的
但是,在处理 class 端初始化时,加载顺序很重要。未声明的绑定是用 nil 初始化的,因此向 nil 发送消息可能不合适并导致 MessageNotUnderstood 异常。
所以gnu smalltalk加入了包的概念。它是一种描述依赖关系和指导加载顺序的元数据,并最终将定义放入备用命名空间。
大部分答案来自 Smalltalk-80 背后的基本原理。
它在最新的 gnu 实现中可能会有所不同。
参见
- https://www.gnu.org/software/smalltalk/manual/html_node/Namespaces.html
- https://www.gnu.org/software/smalltalk/manual/html_node/Packages.html#Packages
最后一件事:在 Smalltalk-80 中,源代码存储在文件或其他文件中的事实是对用户隐藏的实现细节。
您可以直接在浏览器中编写代码。
最终您会将 method/class/category 导出到 fileOut 中,但绝不会自己编写此文件。
GNU Smalltalk 在这方面有点混合。
我认为有两个很好的答案:
FileStream fileIn: 'afile.st'.
在 GNU Smalltalk 中,您不会 import/include/require 将一个源文件转换为另一个源文件。
解释第一个答案
假设我有文件 foo.st
:
"foo.st"
Object subclass: Foo [
foo [^ 'I am Foo from foo.st']
]
如果我想使用我在 bar.st
中编写的代码中的 class Foo
,我可以在 init
方法中使用 FileStream fileIn: 'foo.st'
的 Bar
:
"bar.st"
Object subclass: Bar [
| barsFoo |
Bar class >> new [
| r |
r := super new.
^ r init.
]
init [
"Combines the contents of foo.st with the current image
and assigns a new Foo to barsFoo."
FileStream fileIn: 'foo.st'.
barsFoo := Foo new.
]
bar [
^ 'I am bar from bar.st'
]
foo [
^ barsFoo foo.
]
]
使用这些 classes 看起来像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'bar.st'
FileStream
st> b := Bar new
a Bar
st> b foo
'I am Foo from foo.st'
到目前为止,这一切看起来都很普通import/include/require。但这并不是真的,因为 init
内部的 FileStream fileIn: 'foo.st'
在运行时 发生 所以我可以输入:
st> f := Foo new
a Foo
st> f foo
'I am Foo from foo.st'
解释第二个答案
我在导入bar.st
后得到一个新的Foo
的原因是因为FileStream fileIn: 'bar.st'
结合了bar.st
的内容和当前的图像.
虽然GNU Smalltalk 使用源代码文件的抽象。 Smalltalk 的底层抽象是图像而不是文件,GNU Smalltalk 和任何其他 Smalltalk 系统一样真实。缺少传统的 IDE 不会改变图像的首要地位。对我来说,作为一个新的 Smalltalk 用户,尤其是一个新的 GNU Smalltalk 用户,这是一个难以理解的抽象概念。
这意味着管理 Bar
对 Foo
的依赖的普通低级逐步方法是首先创建一个已经包含 Foo
的图像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'foo.st'
FileStream
st> ObjectMemory snapshot: 'foo.im'
"Global garbage collection... done"
false
st>
现在我可以启动已经包含Foo
的图像:
$ gst -I foo.im
GNU Smalltalk ready
st> f := Foo new
a Foo
st> f foo
'I am Foo from foo.st'
只要我不积极开发 Foo
与 Bar
并行,我就可以将其 init
更改为:
init [
barsFoo := Foo new.
]
我也可以用 Foo
和 Bar
创建一个新图像:
$ gst -I foo.st
GNU Smalltalk ready
st> FileSteam fileIn: 'bar.st'
FileStream
st> ObjectMemory snapshot: 'foobar.im'
从最新源构建系统
可以创建一个从磁盘读取两个文件的最新版本的对象:
Object subclass: FooBarBuilder [
FooBarBuilder class >> new [
| r |
r := super new.
^ r init.
]
init [
FileStream fileIn: 'foo.st'.
FileStream fileIn: 'bar.st'.
]
]
并构建镜像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'foobarbuilder.st'
FileStream
st> ObjectMemory snapshot: 'foobar.im'
"Global garbage collection... done"
false
st>
使用新图像 foobar.im
允许我在每次创建新 FooBarBuilder
时引入最新版本的 Foo
和 Bar
。不是很漂亮,也有点笨拙,但它可以完成真实构建系统的一些工作。
全部打包
GNU Smalltalk 的包系统可用于将所有必需的文件导入 'clean' Smalltalk 运行时,而不是跟踪多个图像(foo.im
、foobar.im
)。它首先创建一个 package.xml
文件:
<package>
<name>FileImport</name>
<file>foo.st</file>
<file>bar.st</file>
<file>foobarbuilder.st</file>
<filein>foo.st</filein>
<filein>bar.st</filein>
<filein>foobarbuilder.st</filein>
</package>
下一步是 'publishing' 包,以便 GNU Smalltalk 可以使用 gst-package
找到它。在这里,我将其发布到 Linux 中的 home
目录,而不是系统范围的位置(/usr/share/gnu-smalltalk/
on Ubuntu 16.04):
~/smalltalk/fileimport$ gst-package -t ~/.st package.xml
~/smalltalk/fileimport$ gst
GNU Smalltalk ready
st> PackageLoader fileInPackage: 'FileImport'
"Global garbage collection... done"
Loading package FileImport
PackageLoader
st> Foo new
a Foo
st>
结束语
天下没有免费的午餐。 GNU Smalltalk 通过使以熟悉的方式轻松处理文件而有所收获。代价是文件不能很好地与 图像 的抽象和对主要通过修改 运行 图像进行开发的预期相结合。
天下没有免费的午餐。在某些时候,由于阻抗不匹配,来自传统 Smalltalk IDE 的收益可能超过使用源代码文件的熟悉程度。
我是 GNU Smalltalk 的新手。我知道在大多数编程语言中,有一个 import
/#include
/require
命令可以让一个源文件访问另一个源文件的内容。我的问题是,如何在 GNU Smalltalk 中将一个文件导入另一个文件?任何帮助,将不胜感激。谢谢!
它可能在没有 import/include/require/use 的情况下工作,因为 Smalltalk 是后期绑定的:
- class 名称在传统名称为 Smalltalk 的全局命名空间中解析,它是(曾经)将 class 名称(键)关联到 class(值)的 SystemDictionary。这个键值对是一个绑定或关联对象,具体取决于 Smalltalk 品牌。编译器生成的字节码只是推送存储在已编译方法文字中的绑定(理解为指针,绑定是共享的),并提取它的值。
- 如果 class 还不存在,则绑定将存储到名为 Undeclared 的特殊字典中。如果以后定义了这个未声明的变量,那么定义就会改变(即值改变),绑定移动到系统字典。
- 至于方法名称(所谓的选择器),它们直到运行时才完全解析:编译器生成的字节码是:推送接收器。推动论点。发送选择器。
启用后期绑定的原因是您只能通过发送消息与对象进行交互。消息查找是在运行时通过在接收方的 class methodDictionary.
中搜索与选择器对应的键来执行的但是,在处理 class 端初始化时,加载顺序很重要。未声明的绑定是用 nil 初始化的,因此向 nil 发送消息可能不合适并导致 MessageNotUnderstood 异常。
所以gnu smalltalk加入了包的概念。它是一种描述依赖关系和指导加载顺序的元数据,并最终将定义放入备用命名空间。
大部分答案来自 Smalltalk-80 背后的基本原理。
它在最新的 gnu 实现中可能会有所不同。
参见
- https://www.gnu.org/software/smalltalk/manual/html_node/Namespaces.html
- https://www.gnu.org/software/smalltalk/manual/html_node/Packages.html#Packages
最后一件事:在 Smalltalk-80 中,源代码存储在文件或其他文件中的事实是对用户隐藏的实现细节。
您可以直接在浏览器中编写代码。
最终您会将 method/class/category 导出到 fileOut 中,但绝不会自己编写此文件。
GNU Smalltalk 在这方面有点混合。
我认为有两个很好的答案:
FileStream fileIn: 'afile.st'.
在 GNU Smalltalk 中,您不会 import/include/require 将一个源文件转换为另一个源文件。
解释第一个答案
假设我有文件 foo.st
:
"foo.st"
Object subclass: Foo [
foo [^ 'I am Foo from foo.st']
]
如果我想使用我在 bar.st
中编写的代码中的 class Foo
,我可以在 init
方法中使用 FileStream fileIn: 'foo.st'
的 Bar
:
"bar.st"
Object subclass: Bar [
| barsFoo |
Bar class >> new [
| r |
r := super new.
^ r init.
]
init [
"Combines the contents of foo.st with the current image
and assigns a new Foo to barsFoo."
FileStream fileIn: 'foo.st'.
barsFoo := Foo new.
]
bar [
^ 'I am bar from bar.st'
]
foo [
^ barsFoo foo.
]
]
使用这些 classes 看起来像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'bar.st'
FileStream
st> b := Bar new
a Bar
st> b foo
'I am Foo from foo.st'
到目前为止,这一切看起来都很普通import/include/require。但这并不是真的,因为 init
内部的 FileStream fileIn: 'foo.st'
在运行时 发生 所以我可以输入:
st> f := Foo new
a Foo
st> f foo
'I am Foo from foo.st'
解释第二个答案
我在导入bar.st
后得到一个新的Foo
的原因是因为FileStream fileIn: 'bar.st'
结合了bar.st
的内容和当前的图像.
虽然GNU Smalltalk 使用源代码文件的抽象。 Smalltalk 的底层抽象是图像而不是文件,GNU Smalltalk 和任何其他 Smalltalk 系统一样真实。缺少传统的 IDE 不会改变图像的首要地位。对我来说,作为一个新的 Smalltalk 用户,尤其是一个新的 GNU Smalltalk 用户,这是一个难以理解的抽象概念。
这意味着管理 Bar
对 Foo
的依赖的普通低级逐步方法是首先创建一个已经包含 Foo
的图像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'foo.st'
FileStream
st> ObjectMemory snapshot: 'foo.im'
"Global garbage collection... done"
false
st>
现在我可以启动已经包含Foo
的图像:
$ gst -I foo.im
GNU Smalltalk ready
st> f := Foo new
a Foo
st> f foo
'I am Foo from foo.st'
只要我不积极开发 Foo
与 Bar
并行,我就可以将其 init
更改为:
init [
barsFoo := Foo new.
]
我也可以用 Foo
和 Bar
创建一个新图像:
$ gst -I foo.st
GNU Smalltalk ready
st> FileSteam fileIn: 'bar.st'
FileStream
st> ObjectMemory snapshot: 'foobar.im'
从最新源构建系统
可以创建一个从磁盘读取两个文件的最新版本的对象:
Object subclass: FooBarBuilder [
FooBarBuilder class >> new [
| r |
r := super new.
^ r init.
]
init [
FileStream fileIn: 'foo.st'.
FileStream fileIn: 'bar.st'.
]
]
并构建镜像:
$ gst
GNU Smalltalk ready
st> FileStream fileIn: 'foobarbuilder.st'
FileStream
st> ObjectMemory snapshot: 'foobar.im'
"Global garbage collection... done"
false
st>
使用新图像 foobar.im
允许我在每次创建新 FooBarBuilder
时引入最新版本的 Foo
和 Bar
。不是很漂亮,也有点笨拙,但它可以完成真实构建系统的一些工作。
全部打包
GNU Smalltalk 的包系统可用于将所有必需的文件导入 'clean' Smalltalk 运行时,而不是跟踪多个图像(foo.im
、foobar.im
)。它首先创建一个 package.xml
文件:
<package>
<name>FileImport</name>
<file>foo.st</file>
<file>bar.st</file>
<file>foobarbuilder.st</file>
<filein>foo.st</filein>
<filein>bar.st</filein>
<filein>foobarbuilder.st</filein>
</package>
下一步是 'publishing' 包,以便 GNU Smalltalk 可以使用 gst-package
找到它。在这里,我将其发布到 Linux 中的 home
目录,而不是系统范围的位置(/usr/share/gnu-smalltalk/
on Ubuntu 16.04):
~/smalltalk/fileimport$ gst-package -t ~/.st package.xml
~/smalltalk/fileimport$ gst
GNU Smalltalk ready
st> PackageLoader fileInPackage: 'FileImport'
"Global garbage collection... done"
Loading package FileImport
PackageLoader
st> Foo new
a Foo
st>
结束语
天下没有免费的午餐。 GNU Smalltalk 通过使以熟悉的方式轻松处理文件而有所收获。代价是文件不能很好地与 图像 的抽象和对主要通过修改 运行 图像进行开发的预期相结合。
天下没有免费的午餐。在某些时候,由于阻抗不匹配,来自传统 Smalltalk IDE 的收益可能超过使用源代码文件的熟悉程度。