呼んだのは誰?
Posted feedbacks - Flatten
Nested Hiddenとりあえず。
1 2 3 4 5 6 7 8 9 | import sys
def bar():
return foo()
def baz():
return foo()
def foo():
return sys._getframe(1).f_code.co_name
|
callerの使い方をよくわかってませんが。
1 2 3 4 5 6 7 8 9 10 | def foo
/.*`(.+)'/ =~ caller(1)[0]
$1
end
def bar; foo; end
def baz; foo; end
p bar
p baz
|
引数の数がつくのでbar$0になりますが。
1 2 3 4 5 6 7 | def bar = foo
def baz = foo
def foo = {
val trace = (new Throwable).getStackTrace
trace(1).getMethodName
}
|
あまり自信なし。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import inspect
def foo():
print inspect.stack()[1][3]
def bar():
foo()
def baz():
foo()
def main():
bar()
baz()
if __name__ == '__main__':
main()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Test {
public static void main(String[] args) throws Exception {
System.out.println("bar() = " + bar());
System.out.println("bar() = " + baz());
}
public static String bar() {
return foo();
}
public static String baz() {
return foo();
}
public static String foo() {
StackTraceElement[] stackTraceElementArray = new Throwable().getStackTrace();
return stackTraceElementArray[1].getMethodName();
}
}
|
ごめんなさいアップしてから気づきましたが、
System.out.println("bar() = " + baz());
ではなく
System.out.println("baz() = " + baz());
でした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php
function getfuncname()
{
$a=debug_backtrace();
return $a[1]['function'];
}
function func_a()
{
echo getfuncname(),"\n";
}
function func_b()
{
echo getfuncname(),"\n";
}
func_a();
func_b();
?>
|
Schemeの場合、そもそも関数という概念が抽象的で、gotoの飛び先ラベル程度の 意味しか持たないため、「呼び出した関数」の意味を厳密に決めるのは困難です。 (ナイーブな処理系でも、少なくとも末尾呼び出しについては「ソース上のcaller」の 情報は出せません---出せるようにすると言語仕様を満たせないから) なので、ここではGaucheのMOPを使って通常のSchemeとは違う呼び出し セマンティクスを実現してみます。 実行例: gosh> (define-generic bar :class <tracer>) bar gosh> (define-method bar () (foo)) #<<tracer> 0x8e26940> gosh> (define-generic baz :class <tracer>) baz gosh> (define-method baz () (foo)) #<<tracer> 0x8e26900> gosh> (bar) bar gosh> (baz) baz
1 2 3 4 5 6 7 8 9 10 11 | (use gauche.parameter)
(define call-trace (make-parameter '()))
(define-class <tracer> (<generic>) ())
(define-method apply-generic ((gf <tracer>) args)
(parameterize ((call-trace (cons (ref gf'name) (call-trace))))
(next-method)))
(define (foo) ((every-pred pair? car) (call-trace)))
|
ちなみに下のマクロも仕込んでおけば見かけ上は普通の手続き定義のようになります: gosh> (define (bar) (foo)) #<<tracer> 0x8cc0900> gosh> (define (baz) (foo)) #<<tracer> 0x8cc0880> gosh> (bar) bar gosh> (baz) baz ただ、マクロを使ったら何でもありになってしまいますね。 (マクロ内で手続きのトレース用のラッパーを仕込んでしまう、とか。)
1 2 3 4 5 6 7 8 9 | (use util.match)
(define-macro (define . args)
(match args
[((fn . args) . body)
`(begin
((with-module gauche define) ,fn (make <tracer> :name ',fn))
(define-method ,fn ,args . ,body))]
[(var expr)
`((with-module gauche define) ,var ,expr)]))
|
処理系依存、ですよ。
write('')みたいな副作用でもしないと、最適化で「呼び出し」が無かったことになっちゃうので、そうしています。
実行例
$ pl -qs stack.pl
aaa(**)
bbb(**)
?-
1 2 3 4 5 6 | aaa(X):-whoami(X),write('').
bbb(X):-whoami(X),write('').
whoami(X):-prolog_current_frame(F),prolog_frame_attribute(F,parent,X0),prolog_frame_attribute(X0,goal,X).
:-aaa(Xa),writeln(Xa),bbb(Xb),writeln(Xb).
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System;
using System.Diagnostics;
class Program
{
static void Main()
{
Console.WriteLine("bar #=> \"{0}\"", bar());
Console.WriteLine("baz #=> \"{0}\"", baz());
}
static string bar() { return foo(); }
static string baz() { return foo(); }
static string foo()
{
return new StackTrace().GetFrame(1).GetMethod().Name;
}
}
|
アカウントが作成できなかったので匿名投稿します。
var bar = function(){...}
という形式では実現できませんでした。
1 2 3 4 5 6 7 8 9 10 11 12 | var foo = function(){
return arguments.callee.caller.toString().match(/function\s*([^(]+)/)[1];
}
function bar(){
return foo();
}
function baz(){
return foo();
}
alert(bar());
alert(baz());
|
GNU拡張を使用しています。 $ gcc -finstrument-functions -rdynamic caller.c -ldl のような形でコンパイルしてください。 参考 : http://alohakun.blog7.fc2.com/blog-entry-760.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
char *caller_func_name;
__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void *func_address, void *call_site)
{
Dl_info func_info;
Dl_info call_info;
if (dladdr(func_address, &func_info) == 0) {
return;
}
if (strcmp(func_info.dli_sname, "foo") != 0) {
return;
}
if (dladdr(call_site, &call_info) == 0) {
return;
}
caller_func_name = (char *)call_info.dli_sname;
}
char *foo()
{
return caller_func_name;
}
char *bar()
{
return foo();
}
char *baz()
{
return foo();
}
int main()
{
printf("%s\n", bar());
printf("%s\n", baz());
return 0;
}
|
> foo() [1] "foo" > bar() [1] "bar" > baz() [1] "baz"
1 2 3 4 5 6 7 8 9 | foo <- function(){
as.character(sys.calls()[[1]])
}
bar <- function(){
foo()
}
baz <- function(){
foo()
}
|
アカウント作れないですねぇ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use strict;
sub bar {
foo();
}
sub baz {
foo();
}
sub foo {
my $p = (caller(1))[0];
(caller(1))[3] =~ m|^${p}::(.*)|;
}
print bar(),"\n";
print baz(),"\n";
|
処理系依存だな。
1 2 3 4 5 | (defun foo () (caadr (caddr (sb-debug:backtrace-as-list))))
(defun bar () (foo))
(defun baz () (foo))
(bar) ; => BAR
(baz) ; => BAZ
|
1 2 3 4 5 6 7 8 | def foo
caller(1)[0][ /in `(.+)'$/, 1 ]
end
def bar() foo end
def baz() foo end
bar # => "bar"
baz # => "baz"
|
インタプリタ版。
当然だがこういうのはバイトコンパイルすると使えない。他のコードになる。
1 2 3 4 5 6 7 8 9 10 11 12 | (defun foo ()
(with-temp-buffer
(let ((standard-output (current-buffer)))
(backtrace)
(goto-char (point-min))
(forward-line 8)
(forward-sexp 1)
(buffer-substring-no-properties (+ 2 (point-at-bol)) (point)))))
(defun bar () (foo))
(defun baz () (foo))
(bar) ; => "bar"
(baz) ; => "baz"
|
tail call optimizationをやるのでわざとstring.formatを呼んでみる。
1 2 3 4 5 6 7 8 9 10 11 12 | function foo()
return string.gsub(debug.traceback(), "^.+\n.+\n.+`(.+)'.+$", "%1")
end
function bar()
return string.format("%s",foo())
end
function baz()
return string.format("%s",foo())
end
print(bar())
print(baz())
|
すみません。問題の投稿時にログインを忘れていました(^_^;)。 遅まきながら Squeak Smalltalk です。
1 2 | Object >> foo
^thisContext sender selector
|
どうして匿名で投稿したのかなと疑問に思っていたのですが そういうことでしたか(^^;
inspectはまだ使いこなせていませんが。
1 2 3 4 5 6 7 8 9 10 11 12 13 | def caller():
import inspect
return inspect.getouterframes(inspect.currentframe())[1][3]
def foo():
print caller()
def bar():
print caller()
foo(), bar()
# foo
# bar
|
__builtin_return_address() と libbfd の bfd_find_nearest_line() を使ってみました。
% gcc -g caller.c -lbfd
でコンパイルできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h>
#include <stdlib.h>
#include <bfd.h>
static bfd *abfd;
static int size;
static asymbol **symbols;
static asection *section;
const char *foo()
{
int ret;
void *addr;
const char *file;
const char *func;
unsigned int line;
addr = __builtin_return_address(0);
ret = bfd_find_nearest_line(abfd, section, symbols, (long)addr,
&file, &func, &line);
return func;
}
const char *bar()
{
return foo();
}
const char *baz()
{
return foo();
}
int main()
{
abfd = bfd_openr("/proc/self/exe", NULL);
bfd_check_format(abfd, bfd_object);
size = bfd_get_symtab_upper_bound(abfd);
symbols = (asymbol**)malloc(size);
section = bfd_get_section_by_name(abfd, ".debug_info");
printf("%s\n", bar());
printf("%s\n", baz());
free(symbols);
return 0;
}
|
ちゃんとテーブルの形で情報もらえるので文字列から抽出する必要はないかと
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function foo() return debug.getinfo(2).name end
function bar()
local ret = foo()
return ret
end
function baz()
local ret = foo()
return ret
end
print(bar())
print(baz())
|
関数の概念がない言語だと、カバレッジに影響しませんか?
新し目のbashじゃないと無理だと思います。
1 2 3 4 5 6 7 8 9 | foo () {
echo "${FUNCNAME[${#FUNCNAME[@]}-1]}"
}
bar () {
foo
}
baz () {
foo
}
|
Haskellでは名前(識別子)はfirst-classの対象じゃないので式の中では通常の方法では不可能でしょうね。正規順簡約ではなにをcaller、calleeというのかは自明ではないでしょうねぇ。せいぜいコマンドラインから起動したプログラム名くらいかなかのうなのは。。。
1 2 | import System.Environment
main = getProgName >>= putStrLn
|
dbstackでファイル名やそのファイル名の中の何行目で呼ばれたかも取得可能。デバッグ目的の関数なので。
1 2 3 | function foo
st = dbstack;
st(2).name
|
Perl6::Callerを使う例
see: どう書くでリハビリ
PS C:\> bar bar PS C:\> buz buz
1 2 3 4 5 6 7 8 9 10 | function caller
{
if ((get-variable -scope 1 MyInvocation).Value.PositionMessage -match "\+ (\S+) <<<<")
{
$matches[1]
}
}
function bar { caller }
function buz { caller }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | foo := method(
call coroutine callStack at(2) message name
)
bar := method(
foo
)
baz := method(
foo
)
bar println
baz println
|
実行結果 -------------- Called from :bar Called from :baz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | println bar()
println baz()
def bar() { foo() }
def baz() { foo() }
def foo() {
def className = getClass().getName()
def thisObject = new Throwable().getStackTrace().findAll {
stackTraceElement ->
className.equals(stackTraceElement.getClassName())
}
return "Called from :"+ thisObject[1].getProperties().methodName
}
|






にしお
#3384()
Rating1/1=1.00
Ruby で表現すると、 以下のような「fooという関数を呼び出す関数」#bar、#bazがあるとき
このbar, bazの返り値が以下のようになるような関数fooを定義してください。このお題は匿名の「Smalltalk からの挑戦状」を元に作成しました。 確かにこの手のリフレクションの機能が言語によってどう違うのかは興味深いところです。 リフレクションを使う問題をいくつか考えてみたいと思います。 ご投稿ありがとうございました。
[ reply ]