“Dead method context” error in a function

 ̄綄美尐妖づ 提交于 2020-01-11 11:24:09

问题


I am trying to write a isBinary function that checks sent line if it has any non-printable characters (integer value outside range 0-127):

isBinary := [ :sline |
    'Reached isBinary fn.' displayNl.
    sline do: [ :char |           "for each character"
        i := char asInteger.      "convert to integer"
        (i < 0 | i > 127) 
        ifTrue: [^true]. ].       "return true if found unprintable"
    ^false. ].                    "if not found above, return false"

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    ((ff name), ' : ') display.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        (isBinary value: firstline) 
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

isBinary function is reached but, it gives following error (whether the file is binary or not):

$ gst isbinary.st
"Global garbage collection... done"
/home/abcd/binaryfile.x : Reached isBinary fn.
Object: Character value: 16rC0 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
Character(Object)>>badReturnError (Object.st:1389)
String(SequenceableCollection)>>do: (SeqCollect.st:827)
[] in UndefinedObject>>executeStatements (isbinary.st:4)
optimized [] in UndefinedObject>>executeStatements (isbinary.st:16)
[] in Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:903)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:378)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:382)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
Kernel.RecursiveFileWrapper>>namesDo: (VFS.st:396)
Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:902)
File(FilePath)>>allFilesMatching:do: (FilePath.st:775)
Directory class>>allFilesMatching:do: (Directory.st:225)
UndefinedObject>>executeStatements (isbinary.st:11)

Replacing sline do: with sline asArray do: in my code also does not work (same error).

Where is the problem and how can this be solved? Thanks for your help.

Edit: As suggested in the answer and comments, I wrote following code with method in a class and this works. I just want your comments whether this is the right method.

Object subclass: Checker [ 
    isBinary: sline [ 
        'Reached isBinary fn.' displayNl.
        sline do: [ :char |  | i |           "for each character"
            i := char asInteger.             "convert to integer"
            i > 127
            ifTrue: [^true]     "return true if found unprintable"  
        ].       
    ^false. ]      "if no unprintable char found, return false"
].

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    '------------------------------' displayNl.
    ((ff name), ' : ') displayNl.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        ((Checker new) isBinary: firstline)
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

回答1:


Your isBinary variable is bound to a block that contains a so called non-local return, which cannot be executed the way you intend. The reason is that the semantics for a non-local return is to return from the method that defines de block (it's lexical context). If such a method does not exist or it already returned (in other words if the lexical context is not in the calling stack), there is no way to define where the execution flow should return. Hence the error.

To solve this, just create a method #isBinary: that receives an argument sline with the code you wrote for the block. Then call the method instead of evaluating the block. That will work.




回答2:


Following standalone method/block code works by creating a return variable whose value is manipulated in loop if unprintable character is found. The loop is then exited:

isBinary := [ :sline |            "WORKS"
    'Reached isBinary fn: ' display.
    ret := false.                 "return variable initialized to false"
    sline do: [ :char |           "loop for each character in sent line"
        i := char asInteger.      "convert to integer"
        i > 127                   "check if printable"
        ifTrue: [ret := true. exit]].   "ret becomes true if found unprintable; does not work if ^ symbol is used"  
    ret].            "if not found above, ret remains false; ret is returned value"

Above works without creating a class as desired by OP (me!).



来源:https://stackoverflow.com/questions/56086816/dead-method-context-error-in-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!