Menu

#156 stooop redefines [::proc] !

open
stooop (8)
7
2003-04-11
2002-04-23
Don Porter
No

It looks to me like the package stooop is
redefining the commands [::proc]! Yuck!

It seems like a better idea to me for stooop
to define and export [::stooop::proc]. Then
if I want to import it and make use of it as
a replacement for [proc] in my namespace, or
for a replacement for [::proc] more globally,
I have that choice. Currently the stooop
package makes the choice for you.

Discussion

  • Don Porter

    Don Porter - 2002-05-08

    Logged In: YES
    user_id=80530

    stooop also defines [::_proc] ( the renamed [::proc] ).

    Packages in tcllib are not supposed to create commands
    outside their namespaces.

     
  • Nobody/Anonymous

    Logged In: NO

    As English is not my native language, please define what you mean by Yuck!

    Would you also please include a short script which demonstrates the bug?

    Thanks.

    Jean-Luc

     
  • Don Porter

    Don Porter - 2002-05-15

    Logged In: YES
    user_id=80530

    The README for tcllib says:
    ...
    There are some base requirements that a module must meet
    before it
    will be added to tcllib:

    * the module must be a proper Tcl package
    * the module must use a namespace for its commands and
    variables
    * the name of the package must be the same as the name of
    the
    namespace
    ...

    This means that the package "stooop" should only
    define commands that match ::stooop::* .

    However, the package stooop is currently
    defining a command named ::proc and a command
    named ::_proc , against the tcllib policy.

    "Yuck!" means "I'm tasting something bad."

     
  • Nobody/Anonymous

    Logged In: NO

    Stooop needs to overload the proc command in order to make such code transparent:
    proc memberProcedure {this ..} {...
    virtual proc virtualProcedure {this ..} {...
    ...

    Now Consider the following package:

    package provide n 1.0
    namespace eval n {
    proc proc {name arguments args} {
    uplevel 1 ::_proc [list $name $arguments] $args
    }
    namespace export proc
    }

    and the following user code:

    package require n
    rename proc _proc
    namespace import n::*
    proc p {} {}

    Note that in order to use the n package, the user needs to rename proc to the predefined _proc (otherwise n::proc
    will fail), and in the correct order, before importing n exported procedures.

    Do you have anything better, simpler than the above (and backward compatible)?

    Jean-Luc

     
  • Don Porter

    Don Porter - 2002-05-25

    Logged In: YES
    user_id=80530

    Here's the right approach:

    package provide stooop $version
    namespace eval stooop {
    namespace export proc
    ::proc proc {name arguments args} {
    # Use fully qualified name to get Tcl's
    # built-in [proc].
    uplevel 1 ::proc [list $name $arguments] $args
    }
    }

    And the user code:

    namespace eval user {
    package require stooop
    namespace import ::stooop::proc
    proc p {} {}
    }

    It is true that you will not be able to
    [namespace import] the command [::stooop::proc]
    into the global namespace. Depending on your
    perspective, you can attribute this to:

    1) stooop's choice of re-using a command name
    already used by Tcl.
    2) Tcl's choice to put built-in commands directly
    in the global namespace rather than ::tcl.

    Code in the global namespace would be able to use
    the fully qualified [::stooop::proc] to distinguish
    from [::proc].

    I'm not a stooop user or developer, so it's not clear
    to me what you accomplish by overwriting [::proc] and
    whether the alternative above is compatible. However,
    what you are currently doing is incompatible with tcllib.

     
  • Nobody/Anonymous

    Logged In: NO

    dgp wrote:

    > It is true that you will not be able to [namespace import] the command [::stooop::proc] into the global
    namespace. Depending on your perspective, you can attribute this to:
    1) stooop's choice of re-using a command name already used by Tcl.
    2) Tcl's choice to put built-in commands directly in the global namespace rather than ::tcl.
    > Code in the global namespace would be able to use the fully qualified [::stooop::proc] to distinguish
    from [::proc].

    Thank you for the explanations. I understand well now.

    > I'm not a stooop user or developer, so it's not clear to me what you accomplish by overwriting [::proc]
    That is required in order, for example, to detect member procedures (this as first argument), constructors
    (procedure name = class name), setup internal namespace variables, ...

    > and whether the alternative above is compatible.
    I am sure that it is incompatible with most if not all of the stooop code out there.

    > However, what you are currently doing is incompatible with tcllib.
    Well, I could internally use a stooop::proc instead of a proc, but the rename I am afraid cannot be removed.

    So, do you want to remove stooop from tcllib? Should I (can I) do it myself?

    Jean-Luc

     
  • Don Porter

    Don Porter - 2002-05-27

    Logged In: YES
    user_id=80530

    Before you do anything that severe, I'll assign this over
    to Andreas for another opinion. Maybe he will see a way
    to resolve the problem.

    The real problem is that stooop apparently needs to "wrap"
    a command provided by another package (Tcl, in this case)
    and the facilities for doing this with [rename] between
    namespaces do not work well. We were just chatting about
    this a few days ago.

    I think offering an alternative for import is more modular than
    direct wrapping, but perhaps you've got a case where direct
    wrapping is required. I haven't looked into the stooop code
    in detail.

    To help clarify matters, what are the compatibility requirements
    for stooop users? You suggeted that there must continue to
    be a command named [::_proc], but why? Isn't that an "internal"
    detail of stooop, on which users do not have to rely?

     
  • Don Porter

    Don Porter - 2002-05-27
    • assigned_to: jfontain --> andreas_kupries
     
  • Andreas Kupries

    Andreas Kupries - 2002-05-27
    • assigned_to: andreas_kupries --> jfontain
     
  • Nobody/Anonymous

    Logged In: NO

    Don Porter (dgp) wrote:

    >To help clarify matters, what are the compatibility
    requirements for stooop users? You suggeted that there must
    continue to be a command named [::_proc], but why? Isn't
    that an "internal" detail of stooop, on which users do not
    have to rely?

    The requirements are simply that for example the following
    code keeps working:

    class c {
    proc c {this p} {
    set ($this,m) $p
    }
    proc s {} {}
    }
    proc c::~c {this} {}
    virtual proc c::v {this} {}
    delete [new c 0]

    That requires, according to our previous postings, renaming
    the proc command (I rename it to ::_proc, but it could be
    any name, so users do not need to know that particular name)
    so that the stooop::proc can take over and detect whether
    the procedure name is "c" (the constructor, in the "c"
    namespace), "~c" (the destructor), that a procedure first
    argument is "this" (normal member procedure) or not "this"
    (static member procedure). Also a "variable {}" instruction
    is added at the beginning of a member procedure so that it
    is possible to store member data in the empty named
    namespace array using the "($this,...)" conventionnal
    construct.
    Note that virtual member procedures are implemented using
    "stooop::virtual" which takes the "proc" string as first
    argument for visual compatibility with the other member
    fonctions.
    I hope that this summary helps you.
    I will be happy to provide further details if needed.

    Thank you for your help.

    Jean-Luc

     
  • Nobody/Anonymous

    Logged In: NO

    To complement myself:
    > That requires, according to our previous postings, renaming the proc command (I rename it to ::_proc, but it
    could be any name, so users do not need to know that particular name) so that the stooop::proc can take over...

    The thing is that proc needs to be overriden and the only way to do that so that it works in the global namespace is
    to rename ::proc (at least that is the only way I know...).
    Also, stooop::proc obviously needs to invoke the original ::proc for procedures that do not belong to a stooop class.

    Jean-Luc

     
  • Andreas Kupries

    Andreas Kupries - 2002-05-29

    Logged In: YES
    user_id=75003

    Here is a log from discussion on the Tcler's chat about this.

    aku If I understand JF explanations correctly at least
    _proc can be moved into the stooop namespace.
    dgp Yes, fortunately, Tcl's [:roc] does not care what
    namespace it lives in.
    aku ... Off the top of my head I see now way around
    the redefinition of :roc to accomplish what he wants, i.e. use
    of a unadorned [proc] inside of stoop classes to define
    member commands.
    dgp Inside of stooop classes ought to be no problem,
    right? It's outside of them in the global namespace where we
    have trouble.
    aku I retract my opinion about the renamed proc aka
    _proc a bit. stooop does not know if the command it renames
    is the builtin proc, or a different command/procedure from
    another package. If the latter is the case it might require to be
    in the global namespace
    dgp Except for the global namespace, this is why
    importing by the user is better than wrapping by the provider.
    aku I don't know how the [class] command is
    implemented. I deduce from his explanations that [class] sets
    up some namespace and or internal variables and then
    executes the class definition script in the global namespace.
    So [proc] in the class definition is executed in :: . If the class
    def script were executed inside of ::stooop it would use the
    internal stooop:roc
    aku Back to _proc - Because of what I said the safest
    way for stooop might indeed be to leave _proc in ::, as bad as
    that is
    dgp OK, maybe, but that could be changed. My point
    is that stooop is in control at that point and could take care of
    the problem.
    aku I guess so. We have to source-dive.
    aku Anotrher approach could be to use a different
    interp, specially setup to interp class definitions. That way
    only the class commands are possible. It also disables fun
    stuff like loops to generate a series of similar member
    commands

     
  • Don Porter

    Don Porter - 2002-05-29

    Logged In: YES
    user_id=80530

    more chat:

    aku Oh, wait. His example explictly has member commands
    defined outside of the class definition script.
    aku For that he definitely either has to overload [proc], or
    use a qualified name [stoop:roc]. The latter breaks existing
    code
    dgp Or his users have to code in their own namespace.
    dgp But, yes, it's a compatibility problem with his current
    user base.
    dgp I could imagine having an additional command in stooop
    that set up the new [::proc] definition.
    dgp Then for compatibility, current stooop users would have
    to call that command to support their direct call to
    [::proc].
    dgp But stooop itself would not force that definition on
    everyone.
    aku That might be best. Have the user make explicit that
    they use this feature. Still requires them to change their
    code, but not as much as replaced all proc's with
    stooop::proc's

     
  • Nobody/Anonymous

    Logged In: NO

    Thanks for enlightnening discussions, which led me to the following solution proposal:

    namespace eval stooop {
    namespace export class new delete
    variable proc ::proc
    ::proc proc {name arguments args} {
    variable proc
    # invoke the real Tcl proc command:
    uplevel 1 $proc [list $name $arguments] $args
    # unless it is a class procedure:
    # ... stooop specifc code here ...
    }
    ::proc import {args} {
    variable proc
    set proc stooopRenamedProc
    namespace export proc
    uplevel 1 "
    catch {rename proc $proc}
    foreach pattern $args {
    namespace import stooop::\$pattern
    }
    catch {namespace import stooop::proc}
    "
    }
    ::proc class {args} {}
    ::proc new {classOrId args} {}
    ::proc delete {args} {}
    }

    Then the user can optionally use:
    stooop::import *
    instead of the former:
    namespace import stooop::*

    Please let me know what you think.

    Thanks, Jean-Luc

     
  • Don Porter

    Don Porter - 2002-06-11

    Logged In: YES
    user_id=80530

    Thoughts:

    1. I wish this had been ready to be in tcllib-1.3

    2. The idea seems good.

    3. The implementation needs some corrections. ([uplevel] between
    namespaces is always tricky.)

    The export of stooop::proc appears to be conditional on calling
    [stooop::import]. Is that right? Is [stooop::proc] part of
    the package
    interface or not?

    Our previous analysis indicated that import into the global
    namespace
    needed special treatment. I don't think I see that here.

    Perhaps a sketch of the documentation that would accompany this
    change will help me follow it.

     
  • Nobody/Anonymous

    Logged In: NO

    >1. I wish this had been ready to be in tcllib-1.3
    I wish you had told me as I was not aware 1.3 was about to be released.

    >3. The implementation needs some corrections. ([uplevel] between namespaces is always tricky.)
    Please suggest some corrections. Unfortunately, I cannot do any better than what I proposed...

    > The export of stooop::proc appears to be conditional on calling [stooop::import]. Is that right? Is [stooop::proc]
    part of the package interface or not?

    Since the Tcl proc command was renamed, a new proc is needed to replace it. That is what the "namespace
    export proc" and the "namespace import stooop::proc" do in stooop::import{}. Maybe there is a better way to
    achieve that effect?

    >Our previous analysis indicated that import into the global namespace needed special treatment. I don't think I
    see that here.

    I do not understant the above. What I understood is that the renaming of proc should not be forced on the user, and
    that is what is achieved by the optional use of stooop::import. If the user chooses not to invoke stooop::import,
    then he has to explicitely use stooop::proc in his code.

    >Perhaps a sketch of the documentation that would accompany this change will help me follow it.

    I was waiting for the change to be accepted before writing the documentation, but it is quite simple:

    - if the user does not use stooop::import, then he has to use the qualified stooop procedures, as in:

    stooop::class c {
    stooop::proc c {this} {}
    stooop::proc ~c {this} {}
    }
    stooop::proc c::p {this m} {}
    stooop::delete [stooop::new c]

    If he uses:
    stooop::import *
    then the compatibility with the existing stooop code is maintained (the sample code in one of my previous
    messages should work in that case).

    Jean-Luc

     
  • Don Porter

    Don Porter - 2002-06-11

    Logged In: YES
    user_id=80530

    hmmm... there I go assuming context again... sorry.

    A subscription to the tcllib-devel@lists.sf.net mailing list
    would
    be a good idea.

    I intend to propose revisions, that's why I needed documentation
    of intent. Your comments indicate that you do not want or plan
    for stooop users to use [namespace import] at all. I think
    that's
    a mistake. [namespace import] is the general mechanism, and
    people are going to use it. Offering [stooop::import] in
    addition
    is a good idea if it helps work around the global [::proc]
    problem,
    but [namespace import] should still work, and the docs should be
    clear about what commands are exported as stooop's public
    interface.

    Since we can't make tcllib-1.3 anyway, and other Tcl 8.4-related
    things have quicker deadlines right now, I'll get back to
    this later.

     
  • Don Porter

    Don Porter - 2002-06-11

    Logged In: YES
    user_id=80530

    if you like, you can assign this report to me, then I'll be sure
    not to forget about it.

     
  • Nobody/Anonymous

    Logged In: NO

    > A subscription to the tcllib-devel@lists.sf.net mailing list would be a good idea.
    I would like it, but unfortunately, I have a very bad Internet connection from home and I am not allowed to do that at
    work...

    > I intend to propose revisions, that's why I needed documentation of intent. Your comments indicate that you do
    not want or plan for stooop users to use [namespace import] at all.

    That is incorrect. As a matter of fact, that is how the current version of stooop works. The problem that I overlooked
    is that it also renames proc no matter what, so that the stooop's proc always kicks in, which is needed for stooop
    to work at all, as we have seen in the previous postings.

    > I think that's a mistake. [namespace import] is the general mechanism, and people are going to use it. Offering
    [stooop::import] in addition is a good idea if it helps work around the global [::proc] problem, but [namespace
    import] should still work, and the docs should be clear about what commands are exported as stooop's
    public interface.

    At this time, I believe that it is clear what stooop exports (both in the documentation examples and in the source
    file with the "namespace export" line).
    Now for the proc problem (assuming the stooop code is rewritten based on my latest proposal a couple of
    messages ago):
    - if the user does not want to import anything, then he has to use stooop::proc and other fully qualified stooop
    commands, in which case stooop is a well behaved package
    - the user either has existing stooop code, or wants to use class, new, delete, ... and other commands directly. As
    we have seen in the previous postings, that requires the modified stooop proc to replace the Tcl proc command at
    the global level. That is why I proposed the "stooop::import *" instruction which does just that and that can be used
    as a replacement for the currently used "namespace import stooop::*". This way, the only thing that all the current
    stooop users have to do is to modify a single line of code to use the new and improved stooop.

    I think that it is a good compromise, provided that change and the effects are properly documented, which is the
    first thing I would do once we reach an agreement.

    Jean-Luc

     
  • Don Porter

    Don Porter - 2003-04-11

    Logged In: YES
    user_id=80530

    will look this over again, to see if
    I want to propose any changes
    for tcllib 1.4 release.

     
  • Don Porter

    Don Porter - 2003-04-11
    • priority: 5 --> 7
    • assigned_to: jfontain --> dgp