IT

통일이란 무엇입니까?

lottoking 2020. 6. 7. 10:10
반응형

통일이란 무엇입니까?


Java가 삭제와 함께 매개 변수 다형성 (Generics)을 구현한다는 것을 알고 있습니다. 나는 소거가 무엇인지 이해합니다.

C #이 reification을 통해 파라 메트릭 다형성을 구현한다는 것을 알고 있습니다. 나는 당신이 쓸 수 있음을 알고

public void dosomething(List<String> input) {}
public void dosomething(List<Int> input) {}

또는 일부 매개 변수화 형식의 형식 매개 변수가 무엇인지 런타임에 알 수 있습니다,하지만 난 그것을 이해하지 않는 것이 있다 .

  • 통합 유형이란 무엇입니까?
  • 통일 된 가치는 무엇입니까?
  • 유형 / 값이 확정되면 어떻게됩니까?

Reification은 추상적 인 것을 취하고 구체적인 것을 만드는 과정입니다.

C # 제네릭에서 reification 이라는 용어 제네릭 형식 정의 와 하나 이상의 제네릭 형식 인수 (추상적 인 것)를 결합하여 새로운 제네릭 형식 (구체적인 것) 을 만드는 프로세스를 나타냅니다 .

문구는 다르게, 그것의 정의를 복용하는 과정입니다 List<T>int및 콘크리트 생산 List<int>유형입니다.

더 이해하려면 다음 방법을 비교하십시오.

  • Java 제네릭에서 제네릭 형식 정의는 기본적으로 허용되는 모든 형식 인수 조합에서 공유되는 하나의 구체적 제네릭 형식으로 변환됩니다. 따라서 여러 (소스 코드 레벨) 유형이 하나의 (이진 레벨) 유형에 맵핑되지만 결과적 으로 인스턴스의 유형 인수에 대한 정보는 해당 인스턴스에서 삭제됩니다 (유형 소거) .

    1. 이 구현 기법의 부작용으로 기본적으로 허용되는 유일한 일반 형식 인수는 구체적 형식의 이진 코드를 공유 할 수있는 형식입니다. 이는 저장 위치가 상호 교환 가능한 표현을 갖는 유형을 의미합니다. 이는 참조 유형을 의미합니다. 값 형식을 일반 형식 인수로 사용하려면 해당 형식을 상자에 넣어야합니다 (단순 참조 형식 래퍼에 배치).
    2. 이런 식으로 제네릭을 구현하기 위해 코드가 복제되지 않습니다.
    3. 리플렉션을 사용하여 런타임시 사용 가능했던 유형 정보가 손실됩니다. 이는 제네릭 형식의 특수화 ( 특정 제네릭 인수 조합에 대해 특수 소스 코드 를 사용하는 기능 )가 매우 제한적임을 의미합니다.
    4. 이 메커니즘은 런타임 환경의 지원이 필요하지 않습니다.
    5. Java 프로그램 또는 JVM 기반 언어가 사용할 수있는 유형 정보를 유지 하는 몇 가지 해결 방법이 있습니다.
  • C # 제네릭에서 제네릭 형식 정의는 런타임에 메모리에 유지됩니다. 새로운 구체적 유형이 필요할 때마다 런타임 환경은 일반 유형 정의와 유형 인수를 결합하여 새 유형을 작성합니다 (확인). 그래서 우리 는 런타임에 형식 인수의 각 조합에 대해 새로운 형식을 얻습니다 .

    1. 이 구현 기법을 사용하면 모든 유형의 인수 조합을 인스턴스화 할 수 있습니다. 값 형식을 일반 형식 인수로 사용하면 해당 형식이 자체 구현되므로 boxing이 발생하지 않습니다. ( 권투는 여전히 C #에 존재 하지만 이것은 다른 시나리오에서는 발생하지 않습니다.)
    2. 코드 복제는 문제가 될 수 있지만 실제로는 스마트 한 구현 ( Microsoft .NETMono 포함 )이 일부 인스턴스화를 위해 코드를 공유 할 수 있기 때문에 실제로는 그렇지 않습니다 .
    3. 유형 정보가 유지되므로 리플렉션을 사용하여 유형 인수를 검사하여 어느 정도 전문화 할 수 있습니다. 그러나 일반화 유형 정의가 reification이 발생 하기 전에 컴파일 되기 때문에 전문화의 정도가 제한됩니다 (이는 유형 매개 변수의 제한 조건에 대해 정의컴파일하여 수행 되므로 컴파일러는 특정 유형 인수가없는 경우에도 정의를 "이해"하십시오 .
    4. 이 구현 기술은 런타임 지원 및 JIT 컴파일에 크게 의존합니다 (따라서 C # 제네릭이 iOS와 같은 플랫폼 에서 동적 코드 생성이 제한되는 경우가 있음).
    5. C # 제네릭의 컨텍스트에서 런타임 환경에 따라 수정이 수행됩니다. 그러나 제네릭 형식 정의와 구체적인 제네릭 형식의 차이점을 더 직관적으로 이해 하려면 System.Type클래스를 사용하여 언제든지 직접 리파이닝을 수행 할 수 있습니다 (인스턴스화하는 특정 제네릭 형식 인수 조합이 ' t는 소스 코드에 직접 나타납니다).
  • C ++ 템플릿에서 템플릿 정의는 컴파일 타임에 메모리에 유지됩니다. 소스 코드에서 템플릿 유형의 새 인스턴스화가 필요할 때마다 컴파일러는 템플릿 정의와 템플릿 인수를 결합하여 새 유형을 만듭니다. 따라서 컴파일 타임에 템플릿 인수의 각 조합에 대해 고유 한 유형을 얻 습니다 .

    1. 이 구현 기법을 사용하면 모든 유형의 인수 조합을 인스턴스화 할 수 있습니다.
    2. 이것은 바이너리 코드를 복제하는 것으로 알려져 있지만 충분히 똑똑한 툴 체인은 여전히 ​​이것을 감지하고 일부 인스턴스화를 위해 코드를 공유 할 수 있습니다.
    3. 템플릿 정의 자체는 "컴파일"되지 않으며 구체적인 인스턴스화 만 실제로 컴파일 됩니다. 이것은 컴파일러에 대한 제약이 적고보다 큰 템플릿 전문화를 허용합니다 .
    4. 템플릿 인스턴스화는 컴파일 타임에 수행되므로 여기에서도 런타임 지원이 필요하지 않습니다.
    5. 이 프로세스는 최근 에 특히 Rust 커뮤니티에서 단형 화 라고합니다 . 이 단어는 파라 메트릭 다형성 과 대조적으로 사용 되는데, 이는 제네릭이 유래 한 개념의 이름입니다.

통일 이란 일반적으로 "컴퓨터 과학 이외의 것"을 "실제로 만들기"를 의미합니다.

프로그래밍 에서 언어 자체의 정보에 액세스 할 수 있으면 무언가가 구체화 됩니다.

C #이 수행하고 구체화하지 않은 제네릭과 관련이없는 두 가지 예를 들어, 메소드와 메모리 액세스를 봅시다.

OO 언어에는 일반적으로 메소드 가 있으며 클래스에 바인딩되지는 않지만 유사한 함수갖지 않는 메소드가 많이 있습니다. 따라서 그러한 언어로 메소드를 정의하고 호출하거나 대체 할 수 있습니다. 이러한 모든 언어를 사용하면 실제로 메소드 자체를 프로그램의 데이터로 처리 할 수 ​​있습니다. C # (및 실제로 C #이 아닌 .NET)을 사용 MethodInfo하면 메서드를 나타내는 개체를 사용할 수 있으므로 C # 메서드가 구체화됩니다. C #의 메소드는 "퍼스트 클래스 객체"입니다.

All practical languages have some means to access the memory of a computer. In a low-level language like C we can deal directly with the mapping between numeric addresses used by the computer, so the likes of int* ptr = (int*) 0xA000000; *ptr = 42; is reasonable (as long as we've a good reason to suspect that accessing memory address 0xA000000 in this way won't blow something up). In C# this isn't reasonable (we can just about force it in .NET, but with the .NET memory management moving things around it's not very likely to be useful). C# does not have reified memory addresses.

So, as refied means "made real" a "reified type" is a type we can "talk about" in the language in question.

In generics this means two things.

One is that List<string> is a type just as string or int are. We can compare that type, get its name, and enquire about it:

Console.WriteLine(typeof(List<string>).FullName); // System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Console.WriteLine(typeof(List<string>) == (42).GetType()); // False
Console.WriteLine(typeof(List<string>) == Enumerable.Range(0, 1).Select(i => i.ToString()).ToList().GetType()); // True
Console.WriteLine(typeof(List<string>).GenericTypeArguments[0] == typeof(string)); // True

A consequence of this is that we can "talk about" a generic method's (or method of a generic class) parameters' types within the method itself:

public static void DescribeType<T>(T element)
{
  Console.WriteLine(typeof(T).FullName);
}
public static void Main()
{
  DescribeType(42);               // System.Int32
  DescribeType(42L);              // System.Int64
  DescribeType(DateTime.UtcNow);  // System.DateTime
}

As a rule, doing this too much is "smelly", but it has many useful cases. For example, look at:

public static TSource Min<TSource>(this IEnumerable<TSource> source)
{
  if (source == null) throw Error.ArgumentNull("source");
  Comparer<TSource> comparer = Comparer<TSource>.Default;
  TSource value = default(TSource);
  if (value == null)
  {
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
      do
      {
        if (!e.MoveNext()) return value;
        value = e.Current;
      } while (value == null);
      while (e.MoveNext())
      {
        TSource x = e.Current;
        if (x != null && comparer.Compare(x, value) < 0) value = x;
      }
    }
  }
  else
  {
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
      if (!e.MoveNext()) throw Error.NoElements();
      value = e.Current;
      while (e.MoveNext())
      {
        TSource x = e.Current;
        if (comparer.Compare(x, value) < 0) value = x;
      }
    }
  }
  return value;
}

This doesn't do lots of comparisons between the type of TSource and various types for different behaviours (generally a sign that you shouldn't have used generics at all) but it does split between a code path for types that can be null (should return null if no element found, and must not make comparisons to find the minimum if one of the elements compared is null) and the code path for types that cannot be null (should throw if no element found, and doesn't have to worry about the possibility of null elements).

Because TSource is "real" within the method, this comparison can be made either at runtime or jitting time (generally jitting time, certainly the above case would do so at jitting time and not produce machine code for the path not taken) and we have a separate "real" version of the method for each case. (Though as an optimisation, the machine code is shared for different methods for different reference-type type parameters, because it can be without affecting this, and hence we can reduce the amount of machine code jitted).

(It's not common to talk about reification of generic types in C# unless you also deal with Java, because in C# we just take this reification for granted; all types are reified. In Java, non-generic types are referred to as reified because that is a distinction between them and generic types).


As duffymo already noted, "reification" isn't the key difference.

In Java, generics are basically there to improve compile-time support - it allows you to use strongly typed e.g. collections in your code, and have type safety handled for you. However, this only exists at compile-time - the compiled bytecode no longer has any notion of generics; all the generic types are transformed into "concrete" types (using object if the generic type is unbounded), adding type conversions and type checks as needed.

In .NET, generics are an integral feature of the CLR. When you compile a generic type, it stays generic in the generated IL. It's not just transformed into non-generic code as in Java.

This has several impacts on how generics work in practice. For example:

  • Java has SomeType<?> to allow you to pass any concrete implementation of a given generic type. C# cannot do this - every specific (reified) generic type is its own type.
  • Unbounded generic types in Java mean that their value is stored as an object. This can have a performance impact when using value types in such generics. In C#, when you use a value type in a generic type, it stays a value type.

To give a sample, let's suppose you have a List generic type with one generic argument. In Java, List<String> and List<Int> will end up being the exact same type at runtime - the generic types only really exist for compile-time code. All calls to e.g. GetValue will be transformed to (String)GetValue and (Int)GetValue respectively.

In C#, List<string> and List<int> are two different types. They are not interchangeable, and their type-safety is enforced in runtime as well. No matter what you do, new List<int>().Add("SomeString") will never work - the underlying storage in List<int> is really some integer array, while in Java, it is necessarily an object array. In C#, there are no casts involved, no boxing etc.

This should also make it obvious why C# can't do the same thing as Java with SomeType<?>. In Java, all generic types "derived from" SomeType<?> end up being the exact same type. In C#, all the various specific SomeType<T>s are their own separate type. Removing compile-time checks, it's possible to pass SomeType<Int> instead of SomeType<String> (and really, all that SomeType<?> means is "ignore compile-time checks for the given generic type"). In C#, it's not possible, not even for derived types (that is, you can't do List<object> list = (List<object>)new List<string>(); even though string is derived from object).

Both implementations have their pros and cons. There's been a few times when I'd have loved to be able to just allow SomeType<?> as an argument in C# - but it simply doesn't make sense the way C# generics work.


Reification is an object-oriented modeling concept.

Reify is a verb that means "make something abstract real".

When you do object oriented programming it's common to model real world objects as software components (e.g. Window, Button, Person, Bank, Vehicle, etc.)

It's also common to reify abstract concepts into components as well (e.g. WindowListener, Broker, etc.)

참고URL : https://stackoverflow.com/questions/31876372/what-is-reification

반응형