kishoreg88
kishoreg88

Reputation: 1

How to call a proc from a particular sourced file if there are multiple sourced files with same proc names?

I am trying to write a wrapper tcl which sources multiple tcl files and these tcl files have some proc which have the same names in more than 1 file. How do I explicitly call for a proc from a particular file?

I searched stack overflow and I came across proc rename, but I am wondering if there is another solution. Perhaps cleaner.

Upvotes: 0

Views: 612

Answers (2)

mrcalvin
mrcalvin

Reputation: 3434

You can organise the source'ed procs in separate namespaces, e.g., by re-using the script names as namespace names:

add.tcl

namespace eval ::[file tail [info script]] {
    proc calculate {a b} {
        return [expr {$a+$b}]
    }
    namespace export calculate
}

sub.tcl

namespace eval ::[file tail [info script]] {
    proc calculate {a b} {
        return [expr {$a-$b}]
    }
    namespace export calculate
}

Then, in your main script, you may switch back and forth between the different proc pools e.g. using [namespace import]:

% source add.tcl
% source sub.tcl
% namespace import -force ::add.tcl::*
% calculate 5 3
8
% namespace import -force ::sub.tcl::*
% calculate 5 3
2

Remarks

  • [info script] returns the currently sourced script file (is set by the source command behind the scenes).
  • Makes sure to [namespace export] the pooled procs. Otherwise, they won't become imported.
  • Using the -force flag on namespace import will silently replace equally named commands (procs) in the target namespace.
  • Using namespaces over slave interpreters (as suggested by Dinesh) is a matter of consequences and your use case: Do the procs need to share some state (variables) or some resources (channels)? Should the procs be restricted to use only files within their source context? etc.
  • You can certainly define your own variant of source that avoids the boilerplate in each and every source'ed script.

Upvotes: 1

Dinesh
Dinesh

Reputation: 16438

It is kind of tricky, but you can go ahead with slave interpreters to distinguish between the files.

add.tcl

proc calculate {a b} {
        return [expr {$a+$b}]
}

sub.tcl

proc calculate {a b} {
        return [expr {$a-$b}]
}

file_src_manager.tcl

array set tclEngine {}
set files  {add.tcl sub.tcl}
foreach f $files {
  # Creating slave interpreter for each files.
  set tclEngine($f) [interp create]
  # Sourcing them in separate interpreter
  if {[catch {interp eval $tclEngine($f) "source $f"} issue]} {
    puts "Failed to source $f. Reason - $issue"
  }
}
# Calling add.tcl file's calculate method
puts [interp eval $tclEngine(add.tcl) "calculate 5 3"]
# Calling sub.tcl file's calculate method
puts [interp eval $tclEngine(sub.tcl) "calculate 5 3"]

Output

8
2

Reference : interp

Upvotes: 1

Related Questions