Live data from Hacker News

A Primer on Type Systems

cs.uaf.edu

11–20 of 35 posts

Re: A Primer on Type Systems

#11
As someone who is extremely unfamiliar with category theory, types, and C++, something is bothering me that I would love to have clarified.

Polymorphic function templates are introduced with addEm:

  template 
  T addEm(T a, U b)
  {
      return a + b;
  }
It seems to me that this is incorrect. From the Wikipedia page on C++ templates [1], a polymorphic function template is described like this:

  template 
  inline T max(T a, T b) {
      return a > b ? a : b;
  }
The first example seems to define a template so that the function takes two arguments of different types, then relies on the compiler to reject inputs for `+' of types not defined for it. (This does not seem to track with the explanation following it, which indicates that addEm should take two arguments of the same type.)

The implication in the first example seems to be that if you want your template to be compatible with more than one type, you must explicitly indicate so in your template parameters. However, the Wikipedia entry seems to indicate that C++ implicitly instantiates object code for as many types as the template is called on at compile time, a function instantiated for each of the types (addEm, addEm, addEm, etc.), and a compilation error resulting if inputs of different types are passed to the template.

Am I missing something? For reference, here is how I would intuit the first example should look, based on my current understanding.

  template 
  T addEm(T a, T b)
  {
      return a + b;
  }
I'll add that given my lack of knowledge of C++, it could well be that the template syntax allows types T and U to be the same in a particular instantiation of the template, but my understanding is that at least they can be different, and why would you intentionally do that in this example?

1. https://en.wikipedia.org/wiki/Template_(C%2B%2B)

Re: A Primer on Type Systems

#12
post #11

As someone who is extremely unfamiliar with category theory, types, and C++, something is bothering me that I would love to have clarified. Polymorphic function templates are introduced with addEm: template T addEm(T a, U b) { return a + b; } It seems to me that this is incorrect. From the Wikipedia page on C++ templates [1], a polymorphic function template is described like this: template inline T max(T a, T b) { re…

I believe that your understanding is correct.

   template 
is a template with one "type parameter" (may not be the correct technical term), whereas

   template 
is a template with two type parameters, and they can be different. (That's why you give two parameters, so that they don't have to be the same.)

Re: A Primer on Type Systems

#13
post #11

As someone who is extremely unfamiliar with category theory, types, and C++, something is bothering me that I would love to have clarified. Polymorphic function templates are introduced with addEm: template T addEm(T a, U b) { return a + b; } It seems to me that this is incorrect. From the Wikipedia page on C++ templates [1], a polymorphic function template is described like this: template inline T max(T a, T b) { re…

I believe that your understanding is correct. template is a template with one "type parameter" (may not be the correct technical term), whereas template is a template with two type parameters, and they can be different . (That's why you give two parameters, so that they don't have to be the same.)

I appreciate the sanity check with a depth and viscerality I can't properly express.

I also apologize to you and anyone reading for any inaccurate terminology on my part.

Re: A Primer on Type Systems

#14
post #8

Interestingly "statically typed" and "dynamically typed" are becoming less exclusive, there are code sniffers that can run static analysis of code to detect potential type incompatibilities during inspection and PHP even now has a group of parse errors that will be raised if incompatible classes definitions are detected i.e. class Foo { function do(): int { return 1; } } class Bar extends Foo { function do(): string…

Snigl [0] has statically typed function signatures, struct fields, bindings etc; but values still carry their type.

It also traces code before running it to eliminate as many type checks as possible.

The categories aren't very helpful from my perspective, same goes for compiler vs. interpreter. All it leads to is endless arguing about definitions and discouraging of novel approaches.

[0] https://gitlab.com/sifoo/snigl#types

Re: A Primer on Type Systems

#15
post #5

Earlier quoted context omitted.

It's more interesting to answer two questions: 1. Can I easily subvert this type system? 2. Can I make this type system map to concepts in the problem domain? In C, the answer to 1 is "yes" and the answer to 2 is "to a limited extent". In fact, in C, you can subvert the type system so easily that it's considered impossible not to, to the extent that using the standard library requires throwing type information away,…

I'd extend 1 to include "can I easily avoid subverting this type system?" Guarantees are better, but as long as I can get help that's enough for a tool to be useful assuming 2. Regarding 2, I've long complained that the conception of types embedded in many systems (and many heads) is very representational and most of the time we don't actually care about representation. The exceptions I typically mention are where we…

I'd also extend 1 to include "can I subvert this type system when I really need to?"

(And to those who would say "You never need to", I don't think you can be quite that dogmatic. The real world includes a lot of unforeseen scenarios...)

Re: A Primer on Type Systems

#16

Earlier quoted context omitted.

I'd extend 1 to include "can I easily avoid subverting this type system?" Guarantees are better, but as long as I can get help that's enough for a tool to be useful assuming 2. Regarding 2, I've long complained that the conception of types embedded in many systems (and many heads) is very representational and most of the time we don't actually care about representation. The exceptions I typically mention are where we…

I'd also extend 1 to include "can I subvert this type system when I really need to ?" (And to those who would say "You never need to", I don't think you can be quite that dogmatic. The real world includes a lot of unforeseen scenarios...)

It's an important question. Systems where you can't ever subvert the type system may be useful in some places (sandboxing) where systems with an escape hatch aren't, and maybe vice-versa (plausibly "in theory", certainly "in practice" IME). The two might be variants of the same underlying language, though - Safe Haskell is at least an attempt in this space; I don't know how well it delivers.

Re: A Primer on Type Systems

#17
post #4

I found this article helpful. Since C is a "strongly typed" language it helps to review what is meant by type. In addition, like #DonaldPShimoda, I liked that the author challenged to the existing notions of type. Good read.

By all definitions, C is not strongly typed.

The author just points to selected links, without going to the links themselves. If you go to the link he points you to [1] where C typing is defined, you find that two of the three links there that claim C to be strongly typed are broken and the third link immediately qualifies the assertion with: "To be precise, relatively strongly-typed app-specific dialects of the not-very-strongly-typed language, C."

[1] http://wiki.c2.com/?StronglyTyped

Re: A Primer on Type Systems

#18
post #8

Interestingly "statically typed" and "dynamically typed" are becoming less exclusive, there are code sniffers that can run static analysis of code to detect potential type incompatibilities during inspection and PHP even now has a group of parse errors that will be raised if incompatible classes definitions are detected i.e. class Foo { function do(): int { return 1; } } class Bar extends Foo { function do(): string…

Snigl [0] has statically typed function signatures, struct fields, bindings etc; but values still carry their type. It also traces code before running it to eliminate as many type checks as possible. The categories aren't very helpful from my perspective, same goes for compiler vs. interpreter. All it leads to is endless arguing about definitions and discouraging of novel approaches. [0] https://gitlab.com/sifoo/snig…

I agree, and I don't think this is a bad trend, once upon a time I think static vs. dynamic was a clear distinction, that distinction is being worn down as we learn more about the value and costs of those approaches - and as that happens we're compromising the approaches to gain more of the value.

In PHP the (mostly) JIT interpretation exposed a weakness where infrequently executed pieces of code were harder to have confidence in. Unit tests and such have raised our confidence but explicit typing can also raise our confidence in an easier manner, both are good to have but having access to more tools just makes our lives easier.

In fact PHP can be pre-cached in bytecode now (which is basically just a traditional compiled approach) and in the default run mode PHP code files are interpreted and then cached to minimize the number of times code needs to be interpreted. The lines between compiled vs. interpreted are getting really fuzzy now and were pretty fuzzy as far back as Java bytecode (which is as far as my memory goes, others may have a better handle on earlier experiments in partial compilation)

Re: A Primer on Type Systems

#19

Earlier quoted context omitted.

I'd extend 1 to include "can I easily avoid subverting this type system?" Guarantees are better, but as long as I can get help that's enough for a tool to be useful assuming 2. Regarding 2, I've long complained that the conception of types embedded in many systems (and many heads) is very representational and most of the time we don't actually care about representation. The exceptions I typically mention are where we…

I'd also extend 1 to include "can I subvert this type system when I really need to ?" (And to those who would say "You never need to", I don't think you can be quite that dogmatic. The real world includes a lot of unforeseen scenarios...)

Aha! I will counter that you never actually want or need to break the type comprehension of your executable but the static analysis of the compiler or dynamic analysis at runtime may be inaccurate with regards to the truth and motivate you to try and subvert it. This may be about what you were thinking when you wrote your comment but I wanted to highlight a small but important difference. I may find a useful bitwise function that takes arguments of type int and really want to execute the same bitwise function on a pair of doubles, in this case the actual type of data I want the function to operate on is "a series of bytes" but the compiler/whatever's typing system may force me to declare the function as taking an IEEE 754 or two's complement integer instead.

In these cases the typing system is constraining you from declaring a type safe operation the right way by forcing you to play within a subset of the universe of valid types.

Re: A Primer on Type Systems

#20
post #19

Earlier quoted context omitted.

I'd also extend 1 to include "can I subvert this type system when I really need to ?" (And to those who would say "You never need to", I don't think you can be quite that dogmatic. The real world includes a lot of unforeseen scenarios...)

Aha! I will counter that you never actually want or need to break the type comprehension of your executable but the static analysis of the compiler or dynamic analysis at runtime may be inaccurate with regards to the truth and motivate you to try and subvert it. This may be about what you were thinking when you wrote your comment but I wanted to highlight a small but important difference. I may find a useful bitwise…

Imagine that you have a binary-only third-party library, one function of which returns an opaque type. Imagine that you want to unpack that and observe the state of some data inside it (perhaps guided by online hints), and the vendor won't give you the ability to do so because 1) they're busy, or 2) they want a lot of money, or 3) they're out of business. You don't want to have to subvert the type system, but you still kind of need to.

And if you're going to tell me that the only reason you need to in this scenario is because the third-party vendor didn't do their job (including creating the types) right, I'd agree. That doesn't actually change what you need to do, though.

Post reply on HN