New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to create instance variables in a block. #105

Open
PeterCamilleri opened this Issue Aug 12, 2016 · 5 comments

Comments

Projects
None yet
1 participant
@PeterCamilleri
Owner

PeterCamilleri commented Aug 12, 2016

The var@: and val@: methods are not available in a procedure block.

They should be available!

@PeterCamilleri

This comment has been minimized.

Show comment
Hide comment
@PeterCamilleri

PeterCamilleri Aug 14, 2016

Owner

Turns out that this is rather more difficult to do than one might realize. Why?

Currently, when an instance variable is created, a method is defined against the receiver of the current method definition. In a block there is no such receiver at the time the code is being compiled. In fact, the context contains very little at all:

>43 .with{{ )context! }}

Context level 2
ctrl => procedure
mode => deferred
"v" => #<XfOOrth::MacroSpec:0x24d1ac0>
"x" => #<XfOOrth::MacroSpec:0x24d1a30>
"var:" => #<XfOOrth::LocalSpec:0x24d19b8>
"val:" => #<XfOOrth::LocalSpec:0x24d1940>
"}}" => #<XfOOrth::MacroSpec:0x24d18b0>

Context level 1
virtual machine => VirtualMachine instance <Main>
mode => execute

Note that there is no receiver, object or class at all.
What do we have then?

At run time, there is the self value. That's about it. Some serious rethink is needed about
whether this is a good idea, and if so, what architectural changes are needed to accommodate
this rather deep change.

Owner

PeterCamilleri commented Aug 14, 2016

Turns out that this is rather more difficult to do than one might realize. Why?

Currently, when an instance variable is created, a method is defined against the receiver of the current method definition. In a block there is no such receiver at the time the code is being compiled. In fact, the context contains very little at all:

>43 .with{{ )context! }}

Context level 2
ctrl => procedure
mode => deferred
"v" => #<XfOOrth::MacroSpec:0x24d1ac0>
"x" => #<XfOOrth::MacroSpec:0x24d1a30>
"var:" => #<XfOOrth::LocalSpec:0x24d19b8>
"val:" => #<XfOOrth::LocalSpec:0x24d1940>
"}}" => #<XfOOrth::MacroSpec:0x24d18b0>

Context level 1
virtual machine => VirtualMachine instance <Main>
mode => execute

Note that there is no receiver, object or class at all.
What do we have then?

At run time, there is the self value. That's about it. Some serious rethink is needed about
whether this is a good idea, and if so, what architectural changes are needed to accommodate
this rather deep change.

@PeterCamilleri

This comment has been minimized.

Show comment
Hide comment
@PeterCamilleri

PeterCamilleri Aug 16, 2016

Owner

Let's look at some options here. There are a bunch of them!

  1. Don't change anything. Methods (currently shared, but soon exclusive ones too) can be used to create instance variables as needed. This is the safest route, but it sorta leaves prototype based object oriented programming in the lurch.

  2. Add var@: and val@: to all procedures with these changes:

  • Allow @methods to default to an instance variable.
  • Don't even bother creating @methods when they are defined.

This will allow instance variables to be created in procedures, but will create a "wild west" of variables. When undeclared variables are referenced, there will be no error, just a poison nil value. This is pretty ugly.

  1. Add var@: and val@: to the global space.
  • Allow @methods to default to an instance variable.
  • Don't even bother creating @methods when they are defined.

This will allow instance variables to be created anywhere, but will create a "wild wild wild west" of variables. When undeclared variables are referenced, there will be no error, just a poison nil value. This is even uglier.

4,5) Make instance variables self routed methods and make that the default in either procedures or globally. Further, add the method at run time. This will generate a runtime error for an undeclared variable. not as good as a compiler error but better than nil value poison. These methods will however be slower than the current embedded code approach.

  1. Have a strict mode (see 1) for use in methods and a lax mode (see 4) for procedures. This will seemingly preserve the benefits of both... or maybe just make things complicated, buggy and hard to understand.
Owner

PeterCamilleri commented Aug 16, 2016

Let's look at some options here. There are a bunch of them!

  1. Don't change anything. Methods (currently shared, but soon exclusive ones too) can be used to create instance variables as needed. This is the safest route, but it sorta leaves prototype based object oriented programming in the lurch.

  2. Add var@: and val@: to all procedures with these changes:

  • Allow @methods to default to an instance variable.
  • Don't even bother creating @methods when they are defined.

This will allow instance variables to be created in procedures, but will create a "wild west" of variables. When undeclared variables are referenced, there will be no error, just a poison nil value. This is pretty ugly.

  1. Add var@: and val@: to the global space.
  • Allow @methods to default to an instance variable.
  • Don't even bother creating @methods when they are defined.

This will allow instance variables to be created anywhere, but will create a "wild wild wild west" of variables. When undeclared variables are referenced, there will be no error, just a poison nil value. This is even uglier.

4,5) Make instance variables self routed methods and make that the default in either procedures or globally. Further, add the method at run time. This will generate a runtime error for an undeclared variable. not as good as a compiler error but better than nil value poison. These methods will however be slower than the current embedded code approach.

  1. Have a strict mode (see 1) for use in methods and a lax mode (see 4) for procedures. This will seemingly preserve the benefits of both... or maybe just make things complicated, buggy and hard to understand.
@PeterCamilleri

This comment has been minimized.

Show comment
Hide comment
@PeterCamilleri

PeterCamilleri Sep 13, 2016

Owner

With the introspect update we get more details:

>43 .with{{ )context! }}
Level   2

Name    ctrl
Value   procedure

Name    mode
Value   deferred

Name    v
Mapping _445
Spec    MacroSpec
Tags    macro
Builds  vm.push(val);
Does    #<Proc:0x1bd2810@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Name    x
Mapping _446
Spec    MacroSpec
Tags    macro
Builds  vm.push(idx);
Does    #<Proc:0x1bd2690@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Name    var:
Mapping _447
Spec    LocalSpec
Tags    immediate
Builds  instance_exec(vm, &vm.context[:_447].does);
Does    #<Proc:0x1bd3158@C:/Sites/fOOrth/lib/fOOrth/library/data_ref_library.rb
        :8 (lambda)>

Name    val:
Mapping _448
Spec    LocalSpec
Tags    immediate
Builds  instance_exec(vm, &vm.context[:_448].does);
Does    #<Proc:0x1bd3128@C:/Sites/fOOrth/lib/fOOrth/library/data_ref_library.rb
        :21 (lambda)>

Name    }}
Mapping _449
Spec    MacroSpec
Tags    macro end
Builds  });
Does    #<Proc:0x1bd2378@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Level   1

Name    vm
Value   #<XfOOrth::VirtualMachine:0x2001a08>

Name    mode
Value   execute

Owner

PeterCamilleri commented Sep 13, 2016

With the introspect update we get more details:

>43 .with{{ )context! }}
Level   2

Name    ctrl
Value   procedure

Name    mode
Value   deferred

Name    v
Mapping _445
Spec    MacroSpec
Tags    macro
Builds  vm.push(val);
Does    #<Proc:0x1bd2810@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Name    x
Mapping _446
Spec    MacroSpec
Tags    macro
Builds  vm.push(idx);
Does    #<Proc:0x1bd2690@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Name    var:
Mapping _447
Spec    LocalSpec
Tags    immediate
Builds  instance_exec(vm, &vm.context[:_447].does);
Does    #<Proc:0x1bd3158@C:/Sites/fOOrth/lib/fOOrth/library/data_ref_library.rb
        :8 (lambda)>

Name    val:
Mapping _448
Spec    LocalSpec
Tags    immediate
Builds  instance_exec(vm, &vm.context[:_448].does);
Does    #<Proc:0x1bd3128@C:/Sites/fOOrth/lib/fOOrth/library/data_ref_library.rb
        :21 (lambda)>

Name    }}
Mapping _449
Spec    MacroSpec
Tags    macro end
Builds  });
Does    #<Proc:0x1bd2378@C:/Sites/fOOrth/lib/fOOrth/compiler/word_specs.rb:41
        (lambda)>

Level   1

Name    vm
Value   #<XfOOrth::VirtualMachine:0x2001a08>

Name    mode
Value   execute

@PeterCamilleri

This comment has been minimized.

Show comment
Hide comment
@PeterCamilleri

PeterCamilleri Jun 2, 2018

Owner

After a very long delay, some fresh ideas on this topic.

What if val@: and var@: in a procedure were immediate methods that did two things:

  1. Inserted code so that when the procedure is run, the instance values/variables are created on whatever self happens to be.

  2. Create local methods so that the rest of the procedure can compile in these local variables.

True, in other procedures these variables would be unavailable, but that's OK. Those other procedure have no connection to the object that the creating procedure used.

Owner

PeterCamilleri commented Jun 2, 2018

After a very long delay, some fresh ideas on this topic.

What if val@: and var@: in a procedure were immediate methods that did two things:

  1. Inserted code so that when the procedure is run, the instance values/variables are created on whatever self happens to be.

  2. Create local methods so that the rest of the procedure can compile in these local variables.

True, in other procedures these variables would be unavailable, but that's OK. Those other procedure have no connection to the object that the creating procedure used.

@PeterCamilleri

This comment has been minimized.

Show comment
Hide comment
@PeterCamilleri

PeterCamilleri Sep 8, 2018

Owner

Done. Docs need to be updated.

Owner

PeterCamilleri commented Sep 8, 2018

Done. Docs need to be updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment