@@ -218,7 +218,7 @@ val futureData = downloadAsync(config*, asyncConfig*)
218
218
val stream = downloadStream(config* , asyncConfig* )
219
219
```
220
220
221
- ## Applications in the Wild
221
+ ## Applications
222
222
223
223
### Requests-Scala
224
224
@@ -802,6 +802,100 @@ values by field name seems like it would be a lot more intuitive than relying on
802
802
order and hoping it lines up between your ` case class ` and the parameter list you are unpacking
803
803
it into.
804
804
805
+ ### Binary Compatibility
806
+
807
+ parameter lists using ` unpack ` should be externally indistinguishable from individually-defined
808
+ parameters. So a library should be able to take a method defining individual parameters
809
+
810
+ ``` scala
811
+ def downloadSimple (url : String ,
812
+ connectTimeout : Int ,
813
+ readTimeout : Int )
814
+ ```
815
+
816
+ And later, perhaps in the interest of code sharing, replace it with a method ` unpack ` ing a `
817
+ case class:
818
+
819
+ ``` scala
820
+ case class RequestConfig (url : String ,
821
+ connectTimeout : Int ,
822
+ readTimeout : Int )
823
+
824
+ def downloadSimple (unpack config : RequestConfig )
825
+ ```
826
+
827
+ And this should require no changes at any callsites, and should not break binary or tasty
828
+ compatibility.
829
+
830
+
831
+ ### Default parameter values
832
+
833
+ As can be seen from some of the other examples in this proposal, ` unpack ` should include
834
+ the default parameter values:
835
+
836
+ ``` scala
837
+ case class RequestConfig (url : String ,
838
+ connectTimeout : Int = 10000 ,
839
+ readTimeout : Int = 10000 )
840
+
841
+ // These two methods definitions should be equivalent
842
+ def downloadSimple (unpack config : RequestConfig )
843
+ def downloadSimple (url : String ,
844
+ connectTimeout : Int = 10000 ,
845
+ readTimeout : Int = 10000 )
846
+ ```
847
+
848
+ Large flat parameter lists often contain default parameters, and usually the user would
849
+ want the same default parameter across all use sites. So default parameters should be maintained
850
+ when ` unpack ` ing a ` case class ` type into the enclosing parameter list.
851
+
852
+ ### ` @unroll ` interaction
853
+
854
+ ` @unroll ` annotations on the parameters of a ` case class ` should be preserved when unpacking
855
+ those parameters into a method ` def `
856
+
857
+ ``` scala
858
+ case class RequestConfig (url : String ,
859
+ @ unroll connectTimeout : Int = 10000 ,
860
+ @ unroll readTimeout : Int = 10000 )
861
+
862
+ // These two methods definitions should be equivalent
863
+ def downloadSimple (unpack config : RequestConfig )
864
+ def downloadSimple (url : String ,
865
+ @ unroll connectTimeout : Int = 10000 ,
866
+ @ unroll readTimeout : Int = 10000 )
867
+ ```
868
+
869
+ We expect that both ` unpack ` and ` unroll ` would be used together frequently: ` unpack ` to
870
+ preserve consistency between different methods in the same version, ` unroll ` to preserve
871
+ binary and tasty compatibility of the same method across different versions. The two goals
872
+ are orthogonal and a library author can be expected to want both at the same time, and so
873
+ ` unpack ` needs to preserve the semantics of ` @unroll ` on each individual unpacked parameter.
874
+
875
+ ### Modifier handling
876
+
877
+ ` case class ` fields can have modifiers like ` val ` , ` var ` , ` private ` , etc. that are not allowed
878
+ in method ` def ` s. ` unpack ` should preserve these modifiers if the enclosing parameter list
879
+ belongs to a ` class ` or ` case class ` , and strip these modifiers if the enclosing parameter list
880
+ belongs to a method ` def `
881
+
882
+ ``` scala
883
+ case class RequestConfig (var url : String ,
884
+ var connectTimeout : Int = 10000 ,
885
+ readTimeout : Int = 10000 )
886
+
887
+ // These two methods definitions should be equivalent
888
+ def downloadSimple (unpack config : RequestConfig )
889
+ def downloadSimple (url : String ,
890
+ connectTimeout : Int = 10000 ,
891
+ readTimeout : Int = 10000 )
892
+ // These two class definitions should be equivalent
893
+ class Foo (unpack config : RequestConfig )
894
+ class Foo (var url : String ,
895
+ var connectTimeout : Int = 10000 ,
896
+ readTimeout : Int = 10000 )
897
+ ```
898
+
805
899
806
900
## Prior Art
807
901
@@ -919,4 +1013,25 @@ fun f() {
919
1013
foo (1 )
920
1014
foo ()
921
1015
}
922
- ```
1016
+ ```
1017
+
1018
+ ## Future Work
1019
+
1020
+ ### Support for tuples and named tuples
1021
+
1022
+ For this initial proposal , we limit `unpack ` an `*` to only work on `case class `es . This is
1023
+ enough for the most painful scenarios [discussed above ](# applications), and matches the most
1024
+ closely : a `case class ` parameter list _exactly_ matches the structure of the enclosing parameter
1025
+ list we `unpack` ing the `case class ` into , and unpacking values via `* ` is also straightforward .
1026
+ However , we could potentially expand this to allow use of `unpack` an `* ` on positional and
1027
+ named tuples .
1028
+
1029
+ While `unpack` / `* ` on `case class ` es is most useful for library authors , `* ` on tuples
1030
+ and named tuples could be of great convenience in application code : method bodies often have
1031
+ local data structures containing tuples or named tuples that get passed as to method calls
1032
+ as parameters , and `* ` could make this a lot more convenient . than having to write
1033
+ `foo(tuple ._1, tuple ._2, tuple ._3)` or similar today .
1034
+
1035
+ `unpack` could also be used to unpack a named tuple into a parameter list , which would
1036
+ work identically to unpacking a `case class ` type except a named tuple would not have
1037
+ any default param values .
0 commit comments