在GNU Smalltalk导入文件

时间:2016-10-06 16:42:50

标签: import smalltalk gnu-smalltalk

我是GNU Smalltalk的新手。我知道在大多数编程语言中,有一个import / #include / require命令可以让一个源文件访问另一个的内容。我的问题是,如何在GNU Smalltalk中将一个文件导入另一个文件?任何帮助,将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:3)

我认为有两个好的答案:

  1. FileStream fileIn: 'afile.st'.

  2. 在GNU Smalltalk中,您不能将一个源文件导入/包含/需要到另一个源文件中。

  3. 解释第一个答案

    假设我有文件foo.st

    "foo.st"
    Object subclass: Foo [
        foo [^ 'I am Foo from foo.st']
    ]
    

    如果我想使用我在Foo内编写的代码中的bar.st类,我可以在FileStream fileIn: 'foo.st' init方法中使用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.
        ]
    ]
    

    使用这些类看起来像:

    $ 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。但事实并非如此,因为FileStream fileIn: 'foo.st'内的init在运行时发生,因此我可以输入:

    st> f := Foo new
    a Foo
    st> f foo
    'I am Foo from foo.st'
    

    解释第二个答案

    导入Foo后我获得新bar.st的原因是因为FileStream fileIn: 'bar.st'bar.st的内容与当前的图片相结合。< / p>

    虽然GNU Smalltalk使用源代码文件的抽象。 Smalltalk的底层抽象是图像而不是文件,与任何其他Smalltalk系统一样,GNU Smalltalk也是如此。缺乏传统的IDE并不会改变图像的首要地位。对我来说,这是一个难以理解的抽象概念,作为新的Smalltalk用户,尤其是新的GNU Smalltalk用户。

    这意味着管理BarFoo的依赖性的普通低级逐步方法是先创建一个已包含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.
    ]
    

    我还可以使用FooBar创建新图片:

    $ 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,每次创建新Foo时,我都会引入最新版本的BarFooBarBuilder。不完全是美丽和善良的kludgey,但它将完成一个真正的构建系统的一些工作。

    将它打包

    而不是跟踪多个图像(foo.imfoobar.im)GNU Smalltalk的软件包系统可以用来将所有必要的文件导入到“清理”中#39 ; Smalltalk运行时。首先创建一个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>
    

    下一步是发布&#39;这个包,所以GNU Smalltalk可以使用gst-package找到它。在这里,我将它发布到Linux中的home目录而不是系统范围的位置(Ubuntu 16.04上的/usr/share/gnu-smalltalk/):

    ~/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的收益可能超过熟悉源代码文件的使用。

答案 1 :(得分:2)

没有import / include / require / use可能会有效,因为Smalltalk是后期绑定的:

  • 类名在传统上名为Smalltalk的全局命名空间中解析,该命名空间是将类名(键)与类(值)相关联的SystemDictionary。此键值对是依赖于Smalltalk品牌的绑定或关联对象。编译器生成的字节代码只是推送绑定(理解指向,绑定是共享的),它存储在编译的方法文字中,并提取它的值。
  • 如果某个类尚不存在,则绑定将存储到名为Undeclared的特殊字典中。如果稍后定义了此未声明的变量,则更改定义(即更改值),并将绑定移至系统字典。
  • 对于方法名称(所谓的选择器),它们直到运行时才被解析:编译器产生的字节码是:推送接收器。推动论点。发送选择器。

启用后期绑定的原因是您只能通过发送消息与对象进行交互。并且通过在接收者的类methodDictionary中搜索对应于选择器的键,在运行时执行消息查找。

但是,在处理类侧初始化时,加载顺序很重要。未声明的绑定用nil初始化,因此向nil发送消息可能是不适当的,并导致MessageNotUnderstood异常。

所以gnu smalltalk添加了包的概念。它是一种元数据,用于描述依赖关系并指导加载顺序,并最终将定义放入备用名称空间。

这个答案的大部分来自Smalltalk-80背后的基本原则 它可能在最新的gnu实现中有所不同 参见

最后一件事:在Smalltalk-80中,源代码存储到文件或其他文件中的事实是用户隐藏的实现细节。
您可以直接在浏览器中编码 最终你会将方法/类/类别导出到fileOut中,但永远不会自己写这个文件 GNU Smalltalk在这方面有点混合。