Index: TODO =================================================================== diff -u -rf177b4dbbb589f91704b1acb8dfbd91fc076335a -r563d2de98a63e09432eb9b0840434ea5e9b20052 --- TODO (.../TODO) (revision f177b4dbbb589f91704b1acb8dfbd91fc076335a) +++ TODO (.../TODO) (revision 563d2de98a63e09432eb9b0840434ea5e9b20052) @@ -3386,12 +3386,16 @@ * removed INTERP macros for MEM_COUNT (since we use now per-thread tables instead of per-interp tables as in the first implementation) + * re-enabled transparency of private method in mixins + * added transparency for per-object private methods + * extended regression test TODO: - fix interp.test for tcl 8.6 - fix xocomm.test for tcl 8.6 - private: + * needed fails since method %s.%s is private ? * maybe let private imply protected * tests for private + mixins * tests for object-specific private methods Index: generic/nsf.c =================================================================== diff -u -re2dd1b5c495922563b325b5249517d28ef1f862e -r563d2de98a63e09432eb9b0840434ea5e9b20052 --- generic/nsf.c (.../nsf.c) (revision e2dd1b5c495922563b325b5249517d28ef1f862e) +++ generic/nsf.c (.../nsf.c) (revision 563d2de98a63e09432eb9b0840434ea5e9b20052) @@ -6646,7 +6646,7 @@ int result = TCL_OK; int cmdFlags = Tcl_Command_flags(cmd); - if (/*(cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) ||*/ + if ((cmdFlags & NSF_CMD_CALL_PRIVATE_METHOD) || ((cmdFlags & NSF_CMD_CLASS_ONLY_METHOD) && !NsfObjectIsClass(object))) { /* * The command is not applicable for objects (i.e. might crash, @@ -9623,6 +9623,11 @@ cmd = FindMethod(object->nsPtr, methodName); /*fprintf(stderr, "lookup for proc in obj %p method %s nsPtr %p => %p\n", object, methodName, object->nsPtr, cmd);*/ + if (cmd + && (flags & ( NSF_CM_LOCAL_METHOD|NSF_CM_IGNORE_PERMISSIONS)) == 0 + && (Tcl_Command_flags(cmd) & NSF_CMD_CALL_PRIVATE_METHOD)) { + cmd = NULL; + } } #if defined(INHERIT_CLASS_METHODS) /* this is not optimized yet, since current class might be checked twice, Index: tests/protected.test =================================================================== diff -u -r0f3ecd0524a309ace0729dbfeb5f299f8bf7a250 -r563d2de98a63e09432eb9b0840434ea5e9b20052 --- tests/protected.test (.../protected.test) (revision 0f3ecd0524a309ace0729dbfeb5f299f8bf7a250) +++ tests/protected.test (.../protected.test) (revision 563d2de98a63e09432eb9b0840434ea5e9b20052) @@ -124,6 +124,115 @@ # +# Use case for private: +# Hide "helper methods of e.g. mixin" +# +nx::Test case private-helper { + + nx::Class create B { + :public method bar {} {return "B.bar [next]"} + :public method baz {} {return "B.baz [next]"} + :create b1 { + :public method baz {} {return "b1.baz [next]"} + } + } + nx::Class create C -superclass B { + :public method bar {} {return "C.bar [next]"} + :public method baz {} {return "C.baz [next]"} + :create c1 { + :public method baz {} {return "c1.baz [next]"} + } + } + + # Behavior without mixin with private methods + ? {b1 bar} "B.bar " + ? {b1 baz} "b1.baz B.baz " + + ? {c1 bar} "C.bar B.bar " + ? {c1 baz} "c1.baz C.baz B.baz " + + # + # Define a mixin with helper methods "bar" and "baz". The helper + # methods are defined as private to avoid interference. + # + nx::Class create M { + :public method foo {} {nsf::my -local bar} + :private method bar {} {nsf::my -local baz} + :private method baz {} {return "M.baz"} + } + + # Behavior with mixin . THe private helper methods are "invisible" + # for invocation and next path. + + B mixin add M + + ? {b1 bar} "B.bar " + ? {b1 baz} "b1.baz B.baz " + + ? {c1 bar} "C.bar B.bar " + ? {c1 baz} "c1.baz C.baz B.baz " + + ? {b1 foo} "M.baz" + ? {c1 foo} "M.baz" +} + + +# +# Use case for private: +# Hide "helper object specific helper methods" +# +nx::Test case object-private-helper { + + nx::Class create B { + :public method bar {} {return "B.bar [next]"} + :public method baz {} {return "B.baz [next]"} + :create b1 { + :public method foo {} {nsf::my -local bar} + :private method bar {} {nsf::my -local baz} + :private method baz {} {return "b1.baz"} + } + } + nx::Class create C -superclass B { + :public method bar {} {return "C.bar [next]"} + :public method baz {} {return "C.baz [next]"} + :create c1 { + :public method foo {} {nsf::my -local bar} + :private method bar {} {nsf::my -local baz} + :private method baz {} {return "c1.baz"} + } + } + + # Behavior of per-object helper methods, which are invisible for + # invocation through "bar" and "baz" + + ? {b1 bar} "B.bar " + ? {b1 baz} "B.baz " + ? {b1 foo} "b1.baz" + + ? {c1 bar} "C.bar B.bar " + ? {c1 baz} "C.baz B.baz " + ? {c1 foo} "c1.baz" + + # + # define a mixin class which shadows "bar" and "baz" + # + nx::Class create M { + :public method bar {} {return "M.bar [next]"} + :public method baz {} {return "M.baz [next]"} + } + B mixin add M + + ? {b1 bar} "M.bar B.bar " + ? {b1 baz} "M.baz B.baz " + ? {b1 foo} "b1.baz" + + ? {c1 bar} "M.bar C.bar B.bar " + ? {c1 baz} "M.baz C.baz B.baz " + ? {c1 foo} "c1.baz" +} + + +# # test private # nx::Test case private { @@ -201,6 +310,9 @@ } + + + # # test "nsf::my -local" on classes #