免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: __BlueGuy__
打印 上一主题 下一主题

[C] Lua 造成的代码冗余太严重了, 这个现状怎么改善? [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
101 [报告]
发表于 2012-11-19 00:41 |只看该作者
starwing83 发表于 2012-11-18 22:47
你这种不行。很可能我在这个文件调用其他文件的函数,在函数里面require(这很正常)。照你这个设计就全乱了。

A中有函数f会用相对路径require? B(甚至也有可能是C、D。。。)中会调用f函数?

A加载的时候就将current-loading-filename记录在A某个私有变量里。
f函数根据这个require。。。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
102 [报告]
发表于 2012-11-19 01:00 |只看该作者
starwing83 发表于 2012-11-18 21:34

现在假设我要载入一个相对模块,比如我们依照Python的习惯。impor .foo载入本文件所在目录下的foo.lua,而..foo载入本文件的父目录下的foo.lua。

首先得取得调用require所在地的那个文件的名字。

这就有问题了。首先,这个require调用所在地未必有名字,可能是:

1. 该函数未必直接在文件里。
2. 调试信息被strip。
3. 该函数未必是在Lua中被调用的。


import .foo和 import ..foo(为什么你的相对路径里没有/? 这不是第1次了。。。)是在哪个文件里出现的? 这个文件又是怎么被加载的?
加载它的时候, 总是在加载一个文件吧? .lua, .so, .o zip://....zip/file.lua 之类的?
将这个文件名暴露给程序员 —— 我也觉得这很脏, 但。。。

如果要相对当前文件加载其他文件, 可以在加载当前文件时把前面提到的文件名记录下来, 然后根据它算出想要的文件。
只要当前文件能暴露出来, 这个计算都不一定需要是require/dofile的责任。
但debug这种方式感觉意思就是: 这信息随时可能变化甚至消失。


starwing83 发表于 2012-11-18 21:34
另外,注意到我给出的那个代码里面debug.getinfo(3)了没?这个3是个硬编码的,不具备可移植性。意思是也许到5.3就变了,得是4了……

这也是我觉得这种相对路径不靠谱的原因。。。

有一个真实例子。。。 在elisp从当前的调用栈往上数若干个(个数从代码中可以数得出来),然后检查一些信息。
工作良好, 在不编译的情况下。。。 编译后就不知道怎么数调用栈了。。。  一个一个试。。。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
103 [报告]
发表于 2012-11-19 01:14 |只看该作者
太长,看的头痛。好吧,回帖不看贴,说说在不同项目中用dofile的理由

1. lua写cgi,cgi文件更新时,需要重新加载。
    确信dofile是重新加载的。
2. 相对路径,文件重名等情况.
    比如我给每颗cpu型号,设计了一套lua文件,文件名函数等都一样,放在不同的目录下。(目录名为CPU型号)。
    要获取该cpu**时,执行该目录下的lua即可。
3. 不但用dofile,还用dostring,被包含的lua程序,分别来自文件和字符串。
    这样项目在移植时,很方便的切换了lua程序的来源。
4. debug,丑则丑矣,问题不大,兼容性更无足轻重。lua环境拿到C源码编译的,发布自然是 lua宿主程序和lua script一起发布。

论坛徽章:
0
104 [报告]
发表于 2012-11-19 05:16 |只看该作者
starwing83 发表于 2012-11-18 17:59
回复 63# OwnWaterloo

C++的class不写存取权限符,就是默认private,不明白?


这就是我在写 c++ 代码的时候一直用 struct 代替 class 的原因。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
105 [报告]
发表于 2012-11-19 06:19 |只看该作者
本帖最后由 starwing83 于 2012-11-19 06:27 编辑
OwnWaterloo 发表于 2012-11-19 00:07
我就是还没来得及写啊。。。 你这到底是要我这就写还是等会写。。。   就现在写吧。。。

C++,Java(Clojure),C#,Python,Elisp,CL,Scheme,它们 —— 或者只说Python之前的那些,因为后面那些的non local jump各有各的不同,也不自称为异常 —— 的异常是可以一路走到底的。
发现错误的点抛异常。 想处理错误的点写try/catch。 不想处理错误的点写try/finally或者析构或者with。 不需要进行exception <-> status code的转换。

C++得单独算, 如果不考虑编译器兼容, 也是可以一路走到底。
C++如果考虑编译器兼容, 就要在编译边界进行 exception <-> status code 的转换。 边界之中, 异常也是可以走到底。
而lua。。。 转换粒度比C++还小是闹哪样。。。


这一个帖子的中心思想就这一个,我就这一起回了。

接前面所说的三个目的(实现手法我就不提了,前贴有):

1. 状态码转异常
2. 异常转状态码
3. finally

首先必须说明的是,我发现你一直没搞明白一点,Lua的异常本身是可以一路走到底的,因为newtry本身在捕获以后会自动rethrow。所以本质上是一路走到底。在“一路走到底”上,单纯newtry足矣。

即,newtry完全等价于C++的析构,或者Python的with。

如果想catch,就写异常转换状态码,如果想throw,就写状态码转换异常。即assert = throw;protect = try/catch,newtry = try/finially。请问还缺啥?

举一个小例子好了:
  1. local socket = require 'socket'
  2. local newtry, protect = socket.newtry, socket.protect

  3. local function no_throw_error()
  4.     return nil, "no_throw error!"
  5. end

  6. local function throw_error()
  7.     error "throw error!"
  8. end

  9. local function f(n, throw)
  10.     if n ~= 1 then -- 模拟多次调用
  11.         f(n-1, throw)
  12.         return "OK"
  13.     end
  14.     -- 我们假设要释放点什么
  15.     try = newtry(function()
  16.         print(debug.traceback "collected!")
  17.     end)
  18.     if throw then
  19.         -- 扔错误的函数,用pcall包裹
  20.         try(pcall(throw_error))
  21.     else
  22.         -- 不扔错误的函数,直接调用
  23.         try(no_throw_error())
  24.     end
  25.     -- 注意,try会rethrow
  26. end

  27. print "test 1"
  28. -- 用protect调用
  29. local res, errmsg = protect(f)(10, "throw")
  30. if not res then
  31.     print("error in f: ", errmsg)
  32.     -- 如果你愿意,error(errmsg)就是rethrow
  33. end
  34. print(res, errmsg)

  35. print "test 2"
  36. -- 用pcall调用
  37. local res, errmsg = pcall(f, 10, not "throw")
  38. if not res then
  39.     print("error in f: ", errmsg[1])
  40. end
  41. print(res, errmsg)
复制代码
执行的结果是

lua  -- "noname\2012-11-19-1.lua"
test 1
collected!
stack traceback:
        noname\2012-11-19-1.lua:19: in function <noname\2012-11-19-1.lua:18>
        [C]: in function 'try'
        noname\2012-11-19-1.lua:23: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function <noname\2012-11-19-1.lua:12>
        [C]: in ?
        noname\2012-11-19-1.lua:33: in main chunk
        [C]: in ?
error in f:     noname\2012-11-19-1.lua:9: throw error!
nil     noname\2012-11-19-1.lua:9: throw error!
test 2
collected!
stack traceback:
        noname\2012-11-19-1.lua:19: in function <noname\2012-11-19-1.lua:18>
        [C]: in function 'try'
        noname\2012-11-19-1.lua:26: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function 'f'
        noname\2012-11-19-1.lua:14: in function <noname\2012-11-19-1.lua:12>
        [C]: in function 'pcall'
        noname\2012-11-19-1.lua:42: in main chunk
        [C]: in ?
error in f:     no_throw error!
false   table: 0056CF50
Hit any key to close this window...


注意一个问题,每层中间,如果需要收异常,就protect,不需要,就放着扔,try本身就保证了东西会被回收。异常是可以一把扔到底的。中间有人protect了,可以error { errmsg } 重新扔;中间try了,会自动重新扔,即使是每次有异常/状态码转换,你也看不见。我想问问你:对于一门异常不是官方支持的语言来说,除了状态码,你还有什么别的办法能执行catch块????难道用函数?这里用函数很浪费好不好!而且你看到了,你根本看不到状态码的转换!

newtry(function()
   print "这里写catch代码"
end)(f)

local err, msg = protect(f)(...) -- 或者pcall(f, ...)
print "这里写finially代码"
-- rethrow? error { msg }

就这么简单。



论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
106 [报告]
发表于 2012-11-19 06:30 |只看该作者
回复 101# OwnWaterloo


    你这个代码会很麻烦的:

require_in_file(module, current_file_name)

……………………

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
107 [报告]
发表于 2012-11-19 06:35 |只看该作者
回复 102# OwnWaterloo


    哥哥你是pythoner么……你不知道这是Python的相对模块载入语法么?

好吧我科普一下吧……如果模块名前带.,代表这个模块是相对本文件的。

如果模块名前面带多个.,每多一个点代表相对本文件的目录的父目录,比如对文件a/b/c/d/e/f.py里面的代码,import ..foo表示载入a/b/c/d/foo.py,而import ....foo表示a/b/foo.py。


这个能OK是因为import是语法…………是编译期处理的,而编译期文件名肯定没被strip掉的。

debug的信息是可能变化/消失,而且必须保持和别人的兼容。反正总的来说就是这货要小心小心再小心,能不用即别用……但是……人肉写current_file_name是不是太脏了点?

论坛徽章:
1
射手座
日期:2013-08-21 13:11:46
108 [报告]
发表于 2012-11-19 10:52 |只看该作者
starwing83 发表于 2012-11-17 14:11
回复 14# liuspring6


恩,最好是ID,因为策划他妈的也不用名字,也是拿ID找.
用拼音,就是纯找抽.....

论坛徽章:
1
2015亚冠之卡尔希纳萨夫
日期:2015-07-14 12:20:38
109 [报告]
发表于 2012-11-19 13:53 |只看该作者

信息量很大。不看了。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
110 [报告]
发表于 2012-11-19 13:55 |只看该作者
starwing83 发表于 2012-11-19 06:19
这一个帖子的中心思想就这一个,我就这一起回了。

接前面所说的三个目的(实现手法我就不提了,前贴有):

1. 状态码转异常
2. 异常转状态码
3. finally

状态码转异常和异常转状态码不是目的! 哪家的异常机制不是一路用到底,而是要不断和状态码进行转换的?



starwing83 发表于 2012-11-19 06:19
首先必须说明的是,我发现你一直没搞明白一点,Lua的异常本身是可以一路走到底的,因为newtry本身在捕获以后会自动rethrow。所以本质上是一路走到底。在“一路走到底”上,单纯newtry足矣。


不要和我乱说。
Lua的异常是指什么? error仍出的东西? 用pcall来保护? 这是Lua自身支持的东西我没说错吧? error直接往上找pcall, 中间什么都不管
为了让error发生时能执行点什么, 就不得不在不能处理错误的时候也去pcall, 就为了能截获error然后执行点什么然后重新error。

异常相比状态码的优势就是在不能处理错误时就不需要检测/传播
但error/pcall挂着non local jump的皮, 行状态码只实。 实际上不能处理错误也要用pcall, 为了能执行点什么东西, 然后又重新error。


你下面的代码和以前给我看的代码不一样了。 以前的:
* newtry 负责状态码 -> 异常, 如果有异常在抛出前执行一段代码
* protect 负责异常 -> 状态码。

我刚才看了一下: http://lua-users.org/wiki/FinalizedExceptions
现在也是这样。

所以你后面贴的代码,以及论述,在你给出解释之前没法讨论。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP