Dmitry Jemerov ([info]yole) wrote,
@ 2008-04-24 16:45:00
Previous Entry  Add to memories!  Tell a Friend!  Next Entry
refactoring puzzler
Нашлась вот забавная задачка. Есть кусок кода:
public enum EEE {
    a(doTest("a")), b(doTest("s"));

    EEE(String s) {
    }

    private static String doTest(String s) {
        System.out.println("s=" + s);
        return s;
    }
}



Задача: выполнить Inline Method для метода doTest(), полностью сохранив семантику программы. Решение есть, но оно не вполне очевидно :)

(а началось всё с невинно выглядящего exception'а)

update: наш вариант под катом


(Post a new comment)


[info]alexshubert
2008-04-24 01:02 pm UTC (link)
не в курсе, что такое inline method
но при условии, что конструктор хоть что-то делает во строкой, переписал бы так:

public enum EEE {
a("a"), b("s");

EEE(String s) {
doTest(String s)
}

private static String doTest(String s) {
System.out.println("s=" + s);
return s;
}
}

(Reply to this)(Thread)


[info]yole
2008-04-24 01:08 pm UTC (link)
Это не годится для всех случаев:

public enum EEE {
  a(doTest("a")), b("b"), c(doSomethingElse(1, 2, 3))
}

(Reply to this)(Parent)


[info]seliv
2008-04-24 01:30 pm UTC (link)
public enum E {
a("a"),
b("s");

{
System.out.println("s=" + name());
}

E(String s) {
}
}

(Reply to this)(Thread)


[info]yole
2008-04-24 01:32 pm UTC (link)
Не годится по той же причине, что и вариант предыдущего комментатора. :)

(Reply to this)(Parent)(Thread)


[info]seliv
2008-04-24 01:50 pm UTC (link)
public enum E {
    a("a") {{System.out.println("s=" + "a");}}, 
    b("b"), 
    c(doSomethingElse(1, 2, 3));

    E(String s) {
    }

//    private static String doTest(String s) {
//        System.out.println("s=" + s);
//        return s;
//    }

    private static String doSomethingElse(int a, int b, int c) {
    	System.out.println("doSomethingElse");
    	return "se";
    }
}

(Reply to this)(Parent)(Thread)


[info]yole
2008-04-24 01:52 pm UTC (link)
Хм. Мы придумали другое решение, но это, кажется, тоже имеет шансы работать. :)

(Reply to this)(Parent)(Thread)


[info]seliv
2008-04-24 01:59 pm UTC (link)
Нет, это не работает.
Во-первых, не совсем эквивалент, т.к. появляется inner class (у следующего комментатора, кстати, тоже два новых класса - A и B)
Во-вторых, не справится с инлайном метода вида
String doTest() {
    return new Date(System.currentTimeMillis()).toString();
}
т.к. никак не вычислить результат функции в статике.

(Reply to this)(Parent)(Thread)


[info]yole
2008-04-24 02:03 pm UTC (link)
Запостил наш вариант внизу. :)

(Reply to this)(Parent)


[info]airatburganov
2008-04-24 01:57 pm UTC (link)
это не работает так как в исходном методе doTest() вызывается раньше конструктора, а тут System.out.println() позже конструктора. Кроме того что делать если строка изменится в doTest()?

Кстати, не могли бы пояснить, почему этот код вообще компилируется? :)))

тем более интересно узнать искомое решение, ничо в голову не приходит...

(Reply to this)(Parent)(Thread)


[info]yole
2008-04-24 02:02 pm UTC (link)
Запостил внизу.

(Reply to this)(Parent)


[info]seliv
2008-04-24 02:03 pm UTC (link)
это не работает так как в исходном методе doTest() вызывается раньше конструктора, а тут System.out.println() позже конструктора.

С чего бы это? Запустите пример:
public class A {
	{ 
		System.out.println("initializer");
	}

	public A() {
		System.out.println("constructor");
	}

	public static void main(String args[]) {
		new A();
	}
}

(Reply to this)(Parent)(Thread)


[info]airatburganov
2008-04-24 02:13 pm UTC (link)
Я не до конца разбираюсь в последовательности вызовов, но вот мой код, на котором я делал выводы, попробуйте запустить, а ваш пример кажется слишком упрощен.

public enum EEE {
a("a") {{System.out.println("s=" + "a");}},
b(doTest("s"));

EEE(String s) {
System.out.println("hello, " + s);
}

private static String doTest(String s) {
System.out.println("s=" + s);
return s;
}

public static void main(String[] args) {
EEE e = EEE.a;
e = EEE.b;
}
}

насчет inner class'а вроде понял :)

(Reply to this)(Parent)(Thread)


[info]seliv
2008-04-24 02:29 pm UTC (link)
Да, здесь с последовательностью вызовов я не разобрался.
Чтобы всё работало согласно моей идее, надо во внутреннем классе также определить конструктор, а в анонимном классе это невозможно.

(Reply to this)(Parent)


[info]seliv
2008-04-24 02:07 pm UTC (link)
Кстати, не могли бы пояснить, почему этот код вообще компилируется? :)))

Для enum под названием "а" создаётся отдельный inner class, наследник базового enum, в котором определяется instance initializer:

Про изменение строки ответил выше - работать, увы, не будет :-(

(Reply to this)(Parent)


[info]antilamer
2008-04-24 01:51 pm UTC (link)
Так чтоль?

enum EEE {
    a(A()), b(B());

    EEE(String s) {}

    private static String A() {
        String s="a";
        System.out.println("s="+s);
        return s;
    }
    private static String B() {
        String s="b";
        System.out.println("s="+s);
        return s;
    }
}

(Reply to this)(Thread)


[info]yole
2008-04-24 01:54 pm UTC (link)
Это как-то плохо подходит под определение "inline method". :)

(Reply to this)(Parent)


[info]yole
2008-04-24 02:02 pm UTC (link)
В общем, у нас это будет работать так:
public enum EEE {
    a(new Object() {
        String evaluate() {
            System.out.println("s=" + "a");
            return "a";
        }
    }.evaluate()),
    b(new Object() {
        String evaluate() {
            System.out.println("s=" + "s");
            return "s";
        }
    }.evaluate());

    EEE(String s) {
    }

}

(Reply to this)(Thread)


[info]seliv
2008-04-24 02:04 pm UTC (link)
А, ну да, первая мысль была, что тут замыкание нужно.
Но закостенелый мозг в этом направлении думать отказался :-(

(Reply to this)(Parent)(Thread)


[info]9000
2008-04-25 01:10 am UTC (link)
Это, кстати, к вопросу о самозарождении в любой достаточно сложной системе реализации половины лиспа %)

(Reply to this)(Parent)


[info]airatburganov
2008-04-24 02:15 pm UTC (link)
здорово! Никогда бы в голову такое не пришло, надо будет почитать про замыкания :)

(Reply to this)(Parent)


[info]antilamer
2008-04-24 02:17 pm UTC (link)
Во! Почти то что я только что придумал :)
Только я не знал, что у анонимного класса можно звать новоопределенные методы.

interface Source<T> {T get();}

public enum EEE {
    a(new Source<String>() {public String get() {
        String s="a";
        System.out.println("s="+s);
        return s;
    }}.get()),

    b(new Source<String>() {public String get() {
        String s="b";
        System.out.println("s="+s);
        return s;
    }}.get());

    EEE(String s) {}
}

(Reply to this)(Parent)


[info]ivan_ghandhi
2008-04-24 02:49 pm UTC (link)
А кстати, если привыкнуть к этому джаваскрипту, то оно само получается где надо и где не надо, и делает ленивое вычисление совсем ленивым.

(Reply to this)(Parent)


[info]9000
2008-04-25 01:12 am UTC (link)
Кстати, я правильно понимаю, что тут тоже возникнут два новых inner класса, только анонимных и одинаковых?

(Reply to this)(Parent)(Thread)


[info]seliv
2008-04-25 10:52 am UTC (link)
Да, возникнут, но два разных - один для константы "a", второй - для "s".
Вероятно, они будут эквивалентны по коду, но отличаться пулом констант.

(Reply to this)(Parent)


[info]khazzar
2008-04-24 02:12 pm UTC (link)
public enum EEE {
a("a"), b("s") { void process(String s){
System.out.println("s=" + s);
}};

EEE(String s) {
process(s);
}

void process(String s) {
// pass
}

\\ private static String doTest(String s) {
\\ System.out.println("s=" + s);
\\ return s;
\\ }
}


минус решения - метод выполняется после вызова конструктора и только со строковым аргументом.
заинлайнить c(doSomethingElse(1, 2, 3)) так не получится

(Reply to this)(Thread)


[info]khazzar
2008-04-24 02:13 pm UTC (link)
не успел и не угадал. дабл фолт :)

(Reply to this)(Parent)


[info]ivan_ghandhi
2008-04-24 02:47 pm UTC (link)
Анонимный класс всандаливать, что ли...

(Reply to this)


[info]aefimov
2008-04-24 09:05 pm UTC (link)
перенести sout в конструктор?

(Reply to this)


Create an Account
Forgot your login?
Login w/ OpenID
English • Español • Deutsch • Русский…