Pre SIP: Named tuples

Given that named tuples types are declared using type aliases, does it make sense to allow recursive types, currently this is invalid code

type Person = (name: String, age: Int, friend: Option[Person])
3 Likes

May also be related, the possibility to directly serialize and deserialize to JSON Objects, which may not be possible if names are totally erased

this one is possible as long as the type is known at the call-site (you can use constValueTuple method to reflect the names to a value) e.g.

inline def pairs[N <: Tuple, V <: Tuple](nt: NamedTuple[N, V]): Unit =
  val names = constValueTuple[N]
  names.zip(nt.toTuple).toList.foreach(println)

scala> pairs((x = 3, y = 7))
(x,3)
(y,7)
2 Likes

There are some discussions over here Pre-SIP: a syntax for aggregate literals - #107 by lihaoyi about the usefulness of partially named tuples in relation to scrapping boilerplate of constructors etc. Would the current Named tuples scheme be possible to extend to partially named tuples and be unified with (some of) the ideas in that thread?

I believe it would be a considerable can of worms but that’s more a gut feeling than backed by data. I’d not try to extend the named tuples proposal with this at this time. It could be added later if needed.

2 Likes

OK, yes can be considered later, if not to hairy. Thanks.

I really like the fact that my “aggregate literal” proposal does not add any new first class concepts to the language (which might interact with other language features in all sorts of ways) but only allows us to write the code that we’re already writing today with less boilerplate. So color me quite sceptical about this idea.

the purpose of it is computing structural types, and to give better meaning to temporary return values - neither of which are addressed by that proposal

4 Likes

I’ve read through the current version of the feature. I very much welcome it!

It’s simple at the core, it prioritizes imho the right things (Tuple :< NamedTuple, with a conversion the other way around), it doesn’t make named tuples some weird kind of hashmaps / objects (order matters!) in the first place (this is imho important as tuples are very basic building blocks for data, much closer to “structs” than to “objects”; “anonymous objects” should be a higher level feature imho), and they’re even super lightweight when it comes to runtime cost. I really like the design. It will imho also make a great base for other features on top in the future! (Maybe we get better usable CStructs in Scala Native, for example?)

But there is one single thing that cough my attention. I think it’s actually a hot candidate for a all time high-score on Scala Puzzlers. It’s the renaming in pattern matching. That behaves just completely unexpected. I had to read this part a few times until I believed that I got it. Very unintuitive.

In this regard I fully support @tarsa’s older remarks to which I answer.

I would really hope the syntax for this one tiny peace of functionality gets changed.

I would really like to the see the proposed as syntax instead.

We established already in some other threads that as has well formed “meta meaning”. It stands for a “rename that introduces a fresh symbol”. That works for import renaming, that works for naming given instances, that works in the other pattern matching proposal. It would also work for this case here imho.

I understand that this would create some “irregularity” in a (quite seldom used form of) pattern matching, but it would save the basic meaning of =, which is clearly assignment.

So please consider this small change request.

Everything else looks great, but this tiny piece looks just odd. It really puzzled me.

It behaves exactly like it should: patterns look the same as expressions, except that in a pattern you can replace a subexpression with an identifier in order to bind said identifier. It would be unfortunate to deviate from this principle.

Actually = is overloaded in Scala and has more than one meaning. One use of = is in val declarations to separate the pattern from the initializer. The named tuple syntax is another, separate thing that just happens to use the same symbol, and this can be clearly seen from languages like JavaScript that use different symbols for the two: = for pattern binding, i. e. const [a, b] = [1, 2], and : for object literals, e. g. {a: 1, b: 2}.

1 Like

I’m not a fan of either named parameter or named tuple, because they are not hygienic, sometime not hygienic is confusing. For example:

def NamedParameterFunction(a: Int, b: Int) = { ... }

val a = 1, b = 2
NamedParameterFunction(b, a)
NamedParameterFunction(a, b)
NamedParameterFunction(a = b, b = a)

What’s the behavior, may be it is too clear for scala expert, but it do increase the learning curve.

Named tuple may intruduce more confusion, for example:

type Something = (a: Int, b: Int)

val something: Something
something match {
  case (b, a) => // what's the behavior ? it is too confusing.
                 // In a hygienic world, both a and b are new identifier here, 
                 // which should be totally different from Something.a or
                 // Something.b, no confusion at all.
}

A member name of a class should only be valid inside the class, when refering the name outside the class, class name or class object should be used instead of that name solely. So case class is always a better solution.