On 01/06/2011 10:30 AM, Denis Washington wrote:
Hi,

First of all, I'd like to introduce myself. My name is Denis Washington, and I am a student living in Berlin, Germany. I just stumbled upon GNU Smalltalk a few months ago, and I must say I love it! I am really impressed by the beauty of Smalltalk, especially when being able to use it in the "for-those-who-can-type" style that GNU Smalltalk supports. Many thanks to Paolo and everyone else who made this happen!

I am currently playing with the idea of implementing GObject Introspection [1] bindings for GNU Smalltalk, which would allow the run-time generation of bindings for GObject libraries with the appropiate introspection metadata. This does not only include GTK+ and Glib, but many others such as Clutter and GStreamer, for which we would then have bindings "for free". I don't know if I have the skills needed to do this (I know C fairly well, but am only learning Smalltalk), but I guess it doesn't hurt to try. ;)

Anyway, here is my actual question. I want to implement the bindings generation lazily - a GObject class should be bound only if and when it is first needed. I looked through the base classes and found out that there is an Autoload class which does something similar, but only does autoloading through file-ins. Therefor, I propose the addition of an AbstractAutoload as a superclass of Autoload where most functionality of Autoload is moved, plus the ability to let subclasses specify how a class is autoloaded. For instance, it could have a class method class:in:loadDo: that allows to create subclasses like the following:

AbstractAutoload subclass: GObjectAutoload [

class: nameSymbol in: aNamespace [
^super
class: nameSymbol
in: aNamespace
load: [
"Create wrapper for GObject class and return it"
];
yourself
]
]

Such an AbstractAutoload would probably also have other uses, for instance for other automatic bindings or similar magic.

What do you think?

With the attached any object that implements #autoload can be used as
a loader.  This ensures that the black magic stays confined in
Autoload/AutoloadClass.  For example:

st> Eval [ Autoload class: #Complex in: Smalltalk loader: (PackageLoader 
packageAt: 'Complex'). nil ]
"Global garbage collection... done"
nil
st> Complex real: 1 imaginary: 2
Loading package Complex
(1+2i)

(Complex is not a great example since the constructor method #i is not present, 
but you get the idea).

Paolo
diff --git a/kernel/Autoload.st b/kernel/Autoload.st
index 4097620..20e6a6c 100644
--- a/kernel/Autoload.st
+++ b/kernel/Autoload.st
@@ -32,10 +32,27 @@
 
 
 
+Kernel.PackageInfo extend [
+    autoload [
+        <category: 'private-autoloading'>
+
+        self fileIn
+    ]
+]
+
+FilePath extend [
+    autoload [
+        <category: 'private-autoloading'>
+
+        self withReadStreamDo: [:rs | rs fileIn ]
+    ]
+]
+
 Namespace current: Kernel [
 
 nil subclass: AutoloadClass [
-    | superClass methodDictionary instanceSpec subClasses instanceVariables 
environment name fileName |
+    "Warning: instance variable indices appear below in #class:in:from:"
+    | superClass methodDictionary instanceSpec subClasses instanceVariables 
environment name loader |
     
     <comment: 'I represent the metaclass of an autoloaded class before it is 
autoloaded.
 Having a proxy for the metaclass as well allows one to send messages to
@@ -43,6 +60,33 @@ the metaclass (such as #methodsFor: to extend it with 
class-side methods)
 and have the class autoloaded.'>
     <category: 'Examples-Useful tools'>
 
+    AutoloadClass class >> class: nameSymbol in: aNamespace loader: aLoader [
+       | autoload behavior newClass |
+       "Create the metaclass and its sole instance"
+       behavior := Behavior new superclass: Autoload.
+
+       "Turn the metaclass into an instance of AutoloadClass.  To do
+        this we create a `prototype' in the form of an array..."
+       newClass := Array new: Kernel.AutoloadClass allInstVarNames size.
+       1 to: behavior class instSize
+           do: [:i | newClass at: i put: (behavior instVarAt: i)].
+
+       newClass
+            at: 6 put: aNamespace;
+            at: 7 put: nameSymbol;
+            at: 8 put: aLoader.
+
+       "... and change its class magically after it is initialized."
+       newClass changeClassTo: Kernel.AutoloadClass.
+
+       "Now create the instance.  We go through some hops because of
+        the very limited set of messages that these classes know
+        about."
+       autoload := behavior new.
+       behavior become: newClass.
+        ^autoload
+    ]
+
     name [
        "Answer the name of the class to be autoloaded"
 
@@ -50,13 +94,6 @@ and have the class autoloaded.'>
        ^name
     ]
 
-    name: aSymbol [
-       "Set to aSymbol the name of the class to be autoloaded"
-
-       <category: 'accessing'>
-       name := aSymbol
-    ]
-
     environment [
        "Answer the namespace in which the class will be autoloaded"
 
@@ -64,59 +101,37 @@ and have the class autoloaded.'>
        ^environment
     ]
 
-    environment: aNamespace [
-       "Set to aNamespace the namespace in which the class will be autoloaded"
-
-       <category: 'accessing'>
-       environment := aNamespace
-    ]
-
-    fileName [
-       "Answer the name of the file from which the class will be autoloaded"
-
-       <category: 'accessing'>
-       ^fileName
-    ]
-
-    fileName: aString [
-       "Set to aString the name of the file from which the class will be 
autoloaded"
-
-       <category: 'accessing'>
-       fileName := aString
-    ]
-
     doesNotUnderstand: aMessage [
        "Load the class and resend the message to its metaclass."
 
        <category: 'accessing'>
-       ^aMessage reinvokeFor: self loadedMetaclass
+       ^aMessage reinvokeFor: self loadedMetaclass_
     ]
 
-    loadedMetaclass [
+    loadedMetaclass_ [
        "File-in the file and answer the metaclass for the new value of the
         association which held the receiver"
 
        <category: 'accessing'>
-       ^self loadedClass class
+       ^self loadedClass_ class
     ]
 
-    loadedClass [
+    loadedClass_ [
        "File-in the file and answer the new value of the association which
         held the receiver"
 
        <category: 'accessing'>
-       | class file |
-       self fileName isNil 
+       | class saveLoader |
+       loader isNil 
            ifFalse: 
-               [file := self fileName.
-               self fileName: nil.
-               self environment at: self name put: nil.
-               FileStream fileIn: file].
-       class := self environment at: self name ifAbsent: [nil].
+               [saveLoader := loader.
+               loader := nil.
+               environment at: name put: nil.
+               saveLoader autoload].
+       class := environment at: name ifAbsent: [nil].
        class isNil 
            ifTrue: 
-               [^Autoload error: 'Autoloaded file should have defined class "' 
, name 
-                           , '" but didn''t'].
+               [^Autoload error: '%1 should have defined class %2.%3 but 
didn''t' % {saveLoader. environment. name asString}].
        ^class
     ]
 ]
@@ -152,32 +167,24 @@ as #methodsFor: to extend it with class-side methods).'>
        <category: 'instance creation'>
        "Check if the file exists."
 
-       | autoload behavior newClass |
-       (FileDescriptor open: fileNameString mode: FileStream read) close.
-
-       "Create the metaclass and its sole instance"
-       behavior := Behavior new superclass: Autoload.
+       | autoload file |
+        file := fileNameString asFile.
+       file withReadStreamDo: [ :rs | ].
 
        "Turn the metaclass into an instance of AutoloadClass.  To do
         this we create a `prototype' in the form of an array and then..."
-       newClass := Array new: Kernel.AutoloadClass allInstVarNames size.
-       1 to: behavior class instSize
-           do: [:i | newClass at: i put: (behavior instVarAt: i)].
+        ^self class: nameSymbol in: aNamespace loader: file
+    ]
 
-       "... change its class magically."
-       newClass changeClassTo: Kernel.AutoloadClass.
+    Autoload class >> class: nameSymbol in: aNamespace loader: aLoader [
+       "Make Smalltalk automatically load the class named nameSymbol
+        and residing in aNamespace from fileNameString when needed"
 
-       "We can now initialize it."
-       newClass
-           name: nameSymbol;
-           fileName: fileNameString;
-           environment: aNamespace.
+       <category: 'instance creation'>
+       "Check if the file exists."
 
-       "Now create the instance.  We go through some hops because of
-        the very limited set of messages that these classes know
-        about."
-       autoload := behavior new.
-       behavior become: newClass.
+       | autoload file |
+        autoload := Kernel.AutoloadClass class: nameSymbol in: aNamespace 
loader: aLoader.
        ^aNamespace at: nameSymbol put: autoload
     ]
 
@@ -194,7 +201,7 @@ as #methodsFor: to extend it with class-side methods).'>
        "Load the class and resend the message to it"
 
        <category: 'accessing'>
-       ^aMessage reinvokeFor: self class loadedClass
+       ^aMessage reinvokeFor: self class loadedClass_
     ]
 ]
 
diff --git a/libgst/files.c b/libgst/files.c
index 4b58bbc..535bba2 100644
--- a/libgst/files.c
+++ b/libgst/files.c
@@ -282,14 +282,14 @@ static const char standard_files[] = {
 
   /* Goodies */
   "DynVariable.st\0"
-  "Autoload.st\0"
   "DLD.st\0"
   "Getopt.st\0"
   "Generator.st\0"
   "StreamOps.st\0"
   "ObjDumper.st\0"
-  "PkgLoader.st\0"
   "Regex.st\0"
+  "PkgLoader.st\0"
+  "Autoload.st\0"
 };
 
 /* The argc and argv that are passed to libgst via gst_smalltalk_args. 
_______________________________________________
help-smalltalk mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/help-smalltalk

Reply via email to