How can I enter multiline methods in the interactive Io interpreter? - iolanguage

I am trying the following sample from 7 Languages in 7 Weeks:
Object ancestors := method(
prototype := self proto
if(prototype != Object,
writeln("Slots of ", prototype type, "\n---------------")
prototype slotNames foreach(slotName, writeln(slotName))
writeln
prototype ancestors))
If I put the code in a file with the rest of the example (e.g. animals.io) and execute it via the command line io animals.io then it works as expected.
However, if I attempt to type the method in manually and execute it for any object, I get the following error:
Exception: Object does not respond to 'prototype'
---------
Object prototype Command Line 1
Object ancestors Command Line 1
Is it possible to enter this multi-line method via the interactive interpreter?

use semicolon as a line separator in REPL.
Object ancestors := method(
prototype := self proto;
if(prototype != Object,
writeln("Slots of ", prototype type, "\n---------------");
prototype slotNames foreach(slotName, writeln(slotName));
writeln;
prototype ancestors))

While the Io REPL allows you to enter multiline statements [1], it unfortunately seems to just concatenate the lines together :(
Io> Object getSlot("ancestors")
==> method(
prototype := self proto if(prototype != Object, writeln("Slots of ", prototype type, "\n---------------") prototype slotNames foreach(slotName, writeln(slotName)) writeln prototype ancestors)
)
[1] - You will probably need ReadLine installed on your OS

Related

Ada - Commando- line reader and processer

A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.

error: "struct" expression not at top level

function check(str,arg;type=DataType,max=nothing,min=nothing,description="")
#argcheck typeof(arg)==type
#argcheck arg>min
#argcheck arg<max
#argcheck typeof(description)==String
return arg
end
function constr(name,arg,field)
return :(function $name($arg,$field)
new(check($name,$arg,$field))
end)
end
macro creatStruct(name,arg)
code = Base.remove_linenums!(quote
struct $name
end
end)
print(arg)
append!(code.args[1].args[3].args,[constr(name,arg.args[1].args[1],arg.args[1].args[2])])
code
end
macro myStruct(name,arg)
#creatStruct name arg
end
#myStruct test12 (
(arg1,(max=10))
)
In my code above I'm trying to build a macro that Creates a struct, and within the struct, you can define an argument with boundaries (max, min) and description, etc.
I'm getting this error:
syntax: "#141#max = 10" is not a valid function argument name
and every time I'm trying to solve it, I get another error like:
LoadError: syntax: "struct" expression not at top level
So, I think my Code/Approach is not that cohesive. Anybody can suggest tips and/or another Approche.
You're attempting to make an argument name max with a default value of 10. The error is about max=10 not being a valid name (Symbol), while max is. The bigger issue is you're trying to put this in the struct expression instead of a constructor method:
struct Foo
bar::Float64
max::Int64
end
# constructor
Foo(bar, max=10) = Foo(bar, max)
So you have to figure out how to make an expression for a method with default values, too.
Your second error means that structs must be defined in the top-level. "Top-level" is like global scope but stricter in some contexts; I don't know the exact difference, but it definitely excludes local scopes (macro, function, etc). It looks like the issue is the expression returned by creatStruct being evaluated as code in myStruct, but the LoadError I'm getting has a different message. In any case, the error goes away if I make sure things stay as expressions:
macro myStruct(name,arg)
:(#creatStruct $name $arg)
end

Lua - Function That Creates Detours

I need to make several detours to various functions and doing it one by one is just not an option. I'm looking for a function that will take a table, ideally, and this table is class. Loop through it and for each key, value pair that is a function make a function pointer with a prefix before the original function name. I have tried several variations to achieve this effect, but they all yield different problems. Some simply will not make detour pointer no matter what you give to them, others make detour pointers but they don't work, and some will overflow the stack or simply not be recognized.
I want to know if there is a way, ie rawsets, metatable overrides, constant looping until they do match, etc to make it so the function can get a table (or a string that has the same name as the table, thus a loadstring method would work here too) and loop through each function and make a working detour pointer...no matter what.
I prefer using the self:prefix_orig_name(...) syntax [... can be replaced with actual args].
Here's 2 variations I have tried with example useage.
-- 1st Method
detours = detours or {}
function detour(object, class) -- Class is an extra arg that I would send if for some reason just sending an object didn't work...it was theory oh'ed
if detours[object] then -- Check if the detour already exists...might be worth remaking it especially if the function gets overridden several times in different places?
print("detour: Previous " .. object .. " detour found, using previous detour")
return
end
for name, func in pairs(class and class or loadstring("return " .. object)()) do
-- the loadstring method here is used because the argument received is a string of the same name as the table...thus loading it will yield a table
if type(func) == "function" then
local execute, error = loadstring(object .. ".custom_detour_" .. name .. " = " .. object .. "." .. name) -- This makes the actual pointer
if error then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. error)
end
local luanch, assert = pcall(execute)
if not luanch then
print("detour Error: " .. " Failed to detour: " .. object .. " Error: " .. assert)
end
end
end
print("Table: " .. object .. " successfully detourd")
detours[object] = true -- tells us we made a detour of this table/string
end
-- 2nd Method
function detour(object) -- Takes a table
for k, v in pairs(object) do
if type(v) == "function" and not detours[k] then
if not object.custom_detour_ then
object.custom_detour_ = clone(object) -- use a simple cloning function (shallow) to put a clone of the main table into a sub table of the main table
end
if object["custom_detour_" .. k] ~= object.custom_detour_[k] then
object["custom_detour_" .. k] = object.custom_detour_[k] -- this makes it so the self:custom_detour_orig_name(...) syntax can be used, if I am not mistaken
end
end
end
end
-- Example Usage:
MyClass = class() -- class function is relatively OOP standard
function MyClass:init()
self._something = true
end
function MyClass:change(value)
self._something = value
end
function MyClass:table_print(tbl) -- just making funcs up
for k, v in pairs(tbl) do
print(v)
end
end
my_class = MyClass:new()
-- 1st Method
detour("MyClass")
--2nd Method
detour(MyClass)
I personally prefer the 1st method or at least a string, because I can log each detour and if a problem arises later on, it makes debugging easier...but I am for whatever will work.
Simple detouring is easy to do with closures; no need for loadstring:
function detour(cls)
local detours = {}
for key, value in pairs(cls) do
if type(value) == "function" then -- note: ignores objects with __call metamethod
detours["custom_detour_"..key] = function(...)
-- Do whatever you want here
return value(...)
end
end
end
for key, value in pairs(detours) do
cls[key] = value
end
end

Preventing Function Overriding in Lua Table

In my program when two functions with the same name are defined for the same table, I want my program to give an error. What's happening is that it's simply just calling the last function and executing it.
Here's a sample code
Class{'Cat'}
function Cat:meow( )
print("Meow!")
end
function Cat:meow()
print("Mmm")
end
kitty = Cat:create()
kitty:meow()
The result of the execution is only: "Mmm"
Instead I want something like an error message to be given.
Unfortunately, __newindex does not intercept assignments to fields which already exist. So the only way to do this is to keep Cat empty and store all its contents in a proxy table.
I don't know the nature of your OOP library, so you'll have to incorporate this example on your own:
local Cat_mt = {}
-- Hide the proxy table in closures.
do
local proxy = {}
function Cat_mt:__index(key)
return proxy[key]
end
function Cat_mt:__newindex(key, value)
if proxy[key] ~= nil then
error("Don't change that!")
end
proxy[key] = value
end
end
Cat = setmetatable({}, Cat_mt)

how to pass a method but not activate it in io language

I want to implement a method dim(x,y) which will assign spaces for a matrix(y rows, x cols).
I want to make "dim(x,y)" more powerful by passing an optional function 'filler' to it and then 'dim' will set the element located at (x,y) to filler(x,y)
my code goes as below:
List2D dim := method(x, y, z,
target := list()
filler := if(z == nil,
method(return nil),
z)
for(i, 1, y,
subTarget := list()
for(j, 1, x,
subTarget append( filler(i,j) ))
target append(subTarget) )
return target)
it worked well when 'dim' is called with 2 arguments,
but failed with
List2D dim(3,2, method(x,y, 10*x+y))
which throwed an exception at line filler := if(z == nil
The exception said nil does not respond to '*'
I realized the argument 'z' got activated undesirably when comparing with nil.
So I'm wondering how to get my 'List2D dim' work properly?
Alright so basically, you'll want something like this:
List2D dim := method(x, y,
target := list
blk := call evalArgAt(2) # Get the third argument, and evaluate it in the context of the sender
if(blk isNil, blk := block setScope(call sender))
for(i, 1, y,
subTarget := list
for(j, 1, x,
subTarget append(blk call(i, j))
target append(subTarget)
)
)
target
)
Basically, what's going on here is since your filler, you want to give it arguments, the easiest method is just to pass in a Block. You can do this with messages, but you in effect, end up setting up your own duplicate of Block anyway if you introduce a new scope, which you should. If the third argument evaluates to nil, then we'll just create a new function and set its scope to the calling context; as if the user had passed in an empty function, which has no argument arty and as such, you can pass arguments to it even if it doesn't define any parameters. The fact we scope it to the caller isn't really needed, but you should always scope blocks to the calling context if you're creating the blocks inside your method call. This will give access to the lexical scope of the calling context inside that block; which you're probably shoving some message the user has supplied in it. When ready, just call that method explicitly using the call method.
If your filler method didn't require any arguments, I'd just grab the raw message argument at the 2nd index, instead of evaluating it. This would yield some major performance improvements for some large matrices.