전체 글

Java - Curiously Recurring Generic Pattern (CRTP)

 

elasticsearch Java 코드에서 발견함.

parent의 generic을 정의하는데, 다시 parent의 generic이 쓰인다! (recursion) - 어떻게 해석해야 하지?

// 부모 - generic AB가 recursive하게 쓰인다?
public abstract class AbstractAggregationBuilder<AB extends AbstractAggregationBuilder<AB>>
    extends AggregationBuilder {...}

// 자식
public class FilterAggregationBuilder extends AbstractAggregationBuilder<FilterAggregationBuilder> {...}

 

child 입장에서 보면, parent가 child로 parametrized 되어있다!

즉 CRTP의 의미는 : “나는 나를 상속하는 애들을 generic으로 쓸꺼야”

 

🤔 CRTP 안쓰고 이걸 achieve 가능할까? → raw use of parameterized class warning 뜬다

// Raw use of parameterized class 'DummyClass' warning 뜸
public class DummyClass<T extends DummyClass> {}

 

 

🤔 어떻게 가능한거지?

Base가 instantiate 될 때, Derived의 정확한 instance를 필요로 하지 않아서 가능하다네

https://stackoverflow.com/a/57507791

class Derived: public Base<Derived> { ... }

 

method chaining and static polymorphism을 위해 C++에서 자주 쓰던 방법인 듯, Java도 사용 가능

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=oidoman&logNo=90145719426

 

 

ChatGPT에 물어본 프롬프트

What's the meaning of below Java generic? How is it recursively using generic T without extending it? `public class DummyClass<T extends DummyClass<T>> { ... } `
더보기

The generic declaration public class DummyClass<T extends DummyClass<T>> is using a pattern known as the Curiously Recurring Generic Pattern (CRTP). In this pattern, a class is parameterized with its own type, creating a recursive relationship between the class and its type parameter.

 

1. public class DummyClass<T extends DummyClass<T>>:

  • DummyClass is a generic class with a type parameter T.
  • The type parameter T is constrained to be a subtype of DummyClass<T>. In other words, T must be a class that extends or implements DummyClass<T>. This constraint enforces the recursive relationship.

 

2. Usage Example:

  • Here is an example of how you might use DummyClass:

public class ConcreteClass extends DummyClass<ConcreteClass> {

        // Additional class implementation

}

 

In this example, ConcreteClass extends DummyClass<ConcreteClass>, adhering to the generic constraint. The recursive relationship is achieved because T in DummyClass<T> is bound to be the same type as the concrete class.

 

3. Recursive Relationship:

  • The recursive nature of this pattern comes from the fact that T is constrained to be a subtype of DummyClass<T>. This means that any subclass of DummyClass must itself be parameterized with its own type.

In summary, the generic declaration public class DummyClass<T extends DummyClass<T>> uses the CRTP pattern to enforce that any concrete subclass of DummyClass must use itself as the type argument, establishing a self-referential relationship.

 

The primary motivations for using the CRTP include:

  1. Method Chaining:
    • The CRTP allows for method chaining in a type-safe manner. Methods in the base class can return the derived type, enabling concise and fluent API designs.
  2. Polymorphism without Virtual Functions:
    • In languages like C++, CRTP can provide a form of static polymorphism without relying on virtual functions and the associated runtime overhead.
  3. Compile-Time Code Generation:
    • By using the CRTP, you can leverage the compiler to generate specialized code for each derived class at compile time. This can lead to more efficient code compared to runtime polymorphism.
  4. Enforcing Relationships:
    • The CRTP can be used to enforce relationships between a base class and its derived classes. This can lead to more maintainable code and catch certain types of errors at compile time.
  5. Avoiding Dynamic Dispatch Overhead:
    • In languages like C++, dynamic dispatch (virtual functions) introduces a performance overhead. CRTP provides a way to achieve some level of polymorphism without incurring this overhead.
  6. Template Metaprogramming:
    • In C++, the CRTP is sometimes used in template metaprogramming to achieve compile-time computations and code generation.

It's important to note that while the CRTP can be a powerful tool in certain situations, it comes with trade-offs, and its usage should be carefully considered. Some developers appreciate its elegance and ability to express certain design patterns, while others prefer alternative approaches, such as using interfaces, composition, or traditional polymorphism.

 

In Java, where true templates and CRTP are not supported as they are in C++, the term is often used to describe patterns that achieve similar effects using generics and self-referencing type parameters, as demonstrated in your example (public class DummyClass<T extends DummyClass<T>>).

 

'<언어> > [Java]' 카테고리의 다른 글

[Java] Why Java Strings are immutable  (0) 2022.04.03
[Java 8] Lambda  (0) 2022.02.24
[Java] OOP 공부  (0) 2022.02.07

+ Recent posts