string

Call method by String or Reference

Sometimes you may need to call a method, but you don’t know which one in advance i.e. you want to postpone the decision to runtime.
There are two basic ways to that :

  • Store the method name as a String and build the “call” on the fly when you need it
  • Store a reference to a method in a variable and then use language specific syntax to invoke the method

For example let say you have written multiple standalone tests and you want to run different combination of them based on different needs. In other words you want to parameterize method calls.

Something along the lines :

run_tests -suite=3,5,8
run_tests -suite=2..5

If you have a few combinations you can hard code them, but it is more flexible to “pick” the tests/methods on the fly.

This is just one example of the need for selecting the function/method at the last moment. In most cases you prepare or store the name in a String.

What follows are examples of how to do this in several languages.

Python

There are many different ways to call a function or a method indirectly. Below you can see most of them.

#shortcut of : def say(*a): print(*a)
say = print

#using eval()
eval("say")("hello")
say_hi = "say('hi')"
eval(say_hi)

#call defined functon via locals
locals()["say"]('boo hoo')

#via reference stored in a dict
funs = { 'sayit' : say }
funs['sayit']('sayit')

# ----- and now ... -----

#methods in a string
class StringMethod:
  
  def say(self, *args) : print(*args)
  
  
sm = StringMethod()

#"create" a method
method = getattr(sm,"say")
method("howdy")

#direct assignment
sm_say = sm.say
sm_say('whats sup')

#unbound
sayit = StringMethod.say
sayit(sm,'bye')


-----

hello
hi
boo hoo
sayit
howdy
whats sup
bye

Java

In Java you have to use Reflection. You do it in two steps :

  • First you create a Method out of the String and a description of the parameters
  • Then you call the .invoke() method with the real values

import java.util.*;
import java.lang.reflect.*;


public class MethodReflection {

  public static <ARG> void say(ARG arg) { System.out.println(arg); }

  public void say_hi() { say("hi"); }
  private void sayit(String str) { say(str); }
  
  public void test() throws Exception {
    //get the class that hold the methods you want to call
    Class<?> klass = MethodReflection.class;//Class.forName("MethodReflection");
    
    //get a method w/o arguments
    Method m1 = klass.getMethod("say_hi");// or getDeclaredMethod()
    m1.invoke(this);
    
    //private method requires getDeclaredMethod(), also using one String argument
    Method m2 = klass.getDeclaredMethod("sayit", String.class);
    m2.invoke(this, "hello");
    
    //unknown argument
    Method m3 = klass.getMethod("say", Object.class);
    //first argument null for static method
    m3.invoke(null, "howdy");
    
  }

  public static void main(String[] args) throws Exception {
    MethodReflection mc = new MethodReflection(); 
    mc.test();
  }
}

-----

hi
hello
howdy

JavaScript

say = console.log

eval("say('hi')")

sayit = "say"
window[sayit]('sayit')

-----

hi
sayit

Random generation

With this post I’m starting a series where I will show you how to implement a functionality on the same topic in multiple languages.

All such posts will be marked with a tag : (multi-language)

We will start with generating random numbers and strings.

JavaScript

function rand_int(min,max=null) {
	if (max == null) { max = min; min = 0 }
	return Math.round(Math.random() * max) + min
}
const az = 'abcdefgijhklmnopqrstuvwxyzABCDEFGIJHKLMNOPQRSTUVWXYZ'
function rand_string(count,chars=az) {
	return Array.from({length:count}, (_,x) => chars[rand_int(52)]).join('')
}
function rand_nums(min,max,count) {
	return Array.from({length:count}, (_,x) => rand_int(min,max))
}
function rand_numstr(min,max,count) {return rand_nums(min,max,count).join('')}

Java

public static int rand(int max) {
	Random r = new Random();
	return r.nextInt(max);
}

public static String rand_numstr(int len) {
	StringBuilder str = new StringBuilder();
	for (int i = 0; i < len; i++) str.append(rand(10));
	return str.toString();
}

public static String rand_string(String characters, int len) {
    Random rng = new Random();
    char[] text = new char[len];
    for (int i = 0; i < len; i++) {
        text[i] = characters.charAt(rng.nextInt(characters.length()));
    }
    return new String(text);
}

public static String rand_string(int len) {
	return rand_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ",len);
}

Python

import numpy as np
import string

def rand_int(min,max,count=1):
   return np.random.randint(min,max,count)
   
def rand_int2(min,max,count=1):#non-repeatable
   return np.random.choice(range(min,max),count,replace=False)
   
def rand_str(count,opt='num'):
  chars = ''
  if opt == 'lower' : chars = string.ascii_lowercase
  elif opt == 'upper' : chars = string.ascii_uppercase
  elif opt == 'str' : chars = string.ascii_letters
  elif opt == 'all' : chars = string.digits + string.ascii_letters
  else : chars = string.digits  
  return ''.join([chars[rand_int(0,len(chars))[0]] for _ in range(count) ])
   
print(rand_int(0,100,10))
print(rand_int2(0,10,10))   
print(rand_str(10))   
print(rand_str(10,'lower'))   
print(rand_str(10,'upper'))   
print(rand_str(10,'str'))
print(rand_str(10,'all'))   

------

[24 50  6 69 69 89 78 24 32  3]
[2 3 0 9 7 6 8 1 5 4]
2123149924
tzuqwomaqv
VWXNTLMUDO
wIbOSUostQ
RDwgVu9QCH

Java : join()

Join list of strings :

//joins Iterable or Collection into a String
public static <T> String join(String delimiter, Iterable<T> lst) {
	StringBuilder str = new StringBuilder();
	Iterator<T> it = lst.iterator();
	while ( it.hasNext() ) {
		str.append(it.next().toString());
		if (it.hasNext()) str.append(delimiter);
	}
	return str.toString();
}