I am trying to build a simple design system for my pet project to share between android and iOS apps.
The definitions of widgets are in the common Kotlin module.
I am trying to write swift UI functions to build actual views:
#ViewBuilder
func widget(widget: MyWidget) -> some View {
switch widget {
case let box1 as MyBox:
box(box: box1)
default:
fatalError("Unsupported widget: \(widget)")
}
}
#ViewBuilder
func box(box: MyBox) -> some View {
ZStack {
ForEach(box.children) { child in
widget(widget: child)
}
}
}
When compiling the project, I get the following error:
Command CompileSwift failed with a nonzero exit code
Removing the recursion (like replacing widget call with a Text) resolves the compilation problem.
Note that these functions are not called anywhere else.
XCode version 14.1
Removing recursive call fixes compiler error
Structs in Swift must have a size that is knowable at compilation. In other words, a struct cannot contain a variably-sized object. A struct can contain an array or string or other variably-sized object by using a constant-sized reference to said object (a pointer, essentially). You can't do this:
struct A {
var b: B
}
struct B {
var a: A
}
But you can do this, because both _a and _b are actually just pointers to arrays (i.e, constant size regardless of size of the array or the objects in the array), and A.b and B.a are computed properties that are not actually stored.
struct A {
var _b: [B]
var b: B {
get {
return _b[0]
}
set(new) {
_b[0] = new
}
}
}
struct B {
var _a: [A]
var a: A? {
get {
return _a[0]
}
set(new) {
_a[0] = new
}
}
}
And you can also do this, because storing a Box<T> value only stores a pointer to a Box<T> object, so the size of the reference does not depend on the size of the referenced value.
class Box<T> {
var value: T
init(value: T) {
self.value = value
}
}
struct A {
var b: Box<B>
}
struct B {
var a: Box<A>
}
Since SwiftUI views are structs, they cannot be recursive. There are multiple ways of creating recursive data structures in Swift, and I don't know enough about SwiftUI to say what approach is appropriate in your use case. You can box stuff in via a wrapper class or wrapping in an array, or you can create a recursive Enum box object via the indirect keyword:
enum Maybe<T> {
case None
indirect case Some(_ value: T)
}
struct A {
var b: Maybe<B>
}
struct B {
var a: Maybe<A>
}
let foo = A(b: .None)
let bar = B(a: .Some(A(b: .None)))
Related
In the example following, I'm calling an instance method of a View using the method directly (saveTitle), and via a pointer to that method (saveAction).
When calling the method, I am passing in the current value of the title variable.
When I call it directly, the current value matches the value inside the method.
When I call it via a pointer to the method, the value inside is the value it was when the struct was first instantiated.
It is almost like there is a new instance of the Struct being created, but without the init method being called a second time.
I suspect this has something to do with how SwiftUI handles #State modifiers, but I'm hoping someone out there will have a better understanding, and be able to enlighten me a bit.
Thanks much for your consideration :)
import SwiftUI
struct EditContentView: View {
#Binding var isPresented: Bool
#State var title: String
var saveAction: ((String) -> Void)?
var body: some View {
TextField("new title", text: $title)
Button("save") {
print("calling saveText")
// this call works as expected, the title inside the saveTitle method is the same as here
saveTitle(title)
print("now calling saveAction, a pointer to saveTitle")
// with this call the title inside the method is different than the passed in title here
// even though they are theoretically the same member of the same instance
saveAction!(title)
isPresented = false
}
}
init(isPresented: Binding<Bool>, title: String) {
print("this method only gets called once")
self._isPresented = isPresented
self._title = State(initialValue: title)
saveAction = saveTitle
}
func saveTitle(_ expected: String) {
if (expected == title) {
print("the title inside this method is the same as before the call")
}
else {
print("expected: \(expected), but got: \(title)")
}
}
}
struct ContentView: View {
#State var title = "Change me"
#State var showingEdit = false
var body: some View {
Text(title)
.onTapGesture { showingEdit.toggle() }
.sheet(isPresented: $showingEdit) {
EditContentView(isPresented: $showingEdit, title: title)
}
}
}
I don't think this is related to #State. It is just a natural consequence of structs having value semantics, i.e.
struct Foo {
init() {
print("This is run only once!")
}
var foo = 1
}
var x = Foo() // Prints: This is run only once!
let y = x // x and y are now two copies of the same *value*
x.foo = 2 // changing one of the copies doesn't affect the other
print(y.foo) // Prints: 1
Your example is essentially just a little more complicated version of the above. If you understand the above, then you can easily understand your SwiftUI case, We can actually simplify your example to one without all the SwiftUI distractions:
struct Foo {
var foo = 1
var checkFooAction: ((Int) -> Void)?
func run() {
checkFoo(expectedFoo: foo)
checkFooAction!(foo)
}
init() {
print("This is run only once!")
checkFooAction = checkFoo
}
func checkFoo(expectedFoo: Int) {
if expectedFoo == foo {
print("foo is expected")
} else {
print("expected: \(expectedFoo), actual: \(foo)")
}
}
}
var x = Foo()
x.foo = 2 // simulate changing the text in the text field
x.run()
/*
Output:
This is run only once!
foo is expected
expected: 2, actual: 1
*/
What happens is that when you do checkFooAction = checkFoo (or in your case, saveAction = saveTitle), the closure captures self. This is like the line let y = x in the first simple example.
Since this is value semantics, it captures a copy. Then the line x.foo = 2 (or in your case, the SwiftUI framework) changes the other copy that the closure didn't capture.
And finally, when you inspect what foo (or title) by calling the closure, you see the unchanged copy, analogous to inspecting y.foo in the first simple example.
If you change Foo to a class, which has reference semantics, you can see the behaviour change. Because this time, the reference to self is captured.
See also: Value and Reference Types
Now you might be wondering, why does saveAction = saveTitle capture self? Well, notice that saveTitle is an instance method, so it requires an instance of EditContentView to call, but in your function type, (String) -> Void, there is no EditContentView at all! This is why it "captures" (a copy of) the current value of self, and says "I'll just always use that".
You can make it not capture self by including EditContentView as one of the parameters:
// this doesn't actually need to be optional
var saveAction: (EditContentView, String) -> Void
assign it like this:
saveAction = { this, title in this.saveTitle(title) }
then provide self when calling it:
saveAction(self, title)
Now you won't get different copies of self flying around.
I'm in the process trying to learn and understand protocols with associated types in swift.
At the same time, I'm learning SwiftUI and taking a course on Udemy.
The app that we will building is a coffee order application.
With that being said, I do not follow the tutorial to the "T" as I tried to structure the app differently, so I can learn to think on my own. The app is nothing too fancy.
The tutorial doesn't use generics and protocols to represent or structure data. It is just a tutorial to showcase SwiftUI.
I created a protocol called Coffee that has a CupSize associated type.
Each coffee Cappuccino, Espresso, and Brewed Coffee confirms to the Coffee protocol.
protocol Priceable {
var cost: Double { get }
}
protocol Coffee {
associatedtype CupSize
var cupSize: CupSize { get }
init(cupSize: CupSize)
}
enum EspressoCupSize {
case small
}
struct Espresso: Coffee, Priceable {
var cupSize = EspressoCupSize.small
var cost: Double { return 3.00 }
}
enum BrewedCoffeeCupSize {
case small
case medium
case large
}
struct BrewedCoffee: Coffee, Priceable {
var cupSize: BrewedCoffeeCupSize
var cost: Double {
switch self.cupSize {
case .small: return 1.00
case .medium: return 2.00
case .large: return 3.00
}
}
}
enum CappuccinoCupSize {
case small
case medium
case large
}
struct Cappuccino: Coffee, Priceable {
var cupSize: CappuccinoCupSize
var cost: Double {
switch self.cupSize {
case .small: return 2.00
case .medium: return 3.00
case .large: return 4.00
}
}
}
Then, I created an Order struct and an OrderManager class.
Order struct has a generic and needs to be a Priceable item.
The idea of a generic priceable item is to support other items in the future in case I want to expand the app...not just coffee.
The idea behind OrderManager is to keep track all the orders and manage the CRUD operations of the orders (still need to implement delete, read, and update).
struct Order<Item: Priceable> {
var name: String
var item: Item
}
class OrderManager<Item> {
private var orders: [Item]
init(orders: [Item]) {
self.orders = orders
}
func add(_ order: Item) {
self.orders.append(order)
}
}
My issue is using OrderManager.
let maryOrder = Order(name: "Mary", item: Espresso())
let sueOrder = Order(name: "Sue", item: BrewedCoffee(cupSize: .medium))
// Dummy Structure
struct Person {}
let orderManager = OrderManager(orders: [
maryOrder,
sueOrder,
Person() // This works!!! Which is not what I want.
])
I want the generic type for OrderManager to be an Order, but since Order has its own generic type of Priceable, I cannot seem to find the correct answer or find the correct syntax.
Things I have tried to get OrderManager to work
class OrderManager<Order> {} // Does not work because Order needs a generic type
class OrderManager<Order<Priceable>> // Still does not work
class OrderManager<Item: Priceable, Order<Item> {} // Still does not work.
// and I tried other solutions, but I cannot get this to work
// Also, when I think I got the right syntax, I cannot add Mary and Sue's orders to
// OrderManager because Mary's item is Espresso and Sue's item is BrewedCoffee
How can I get OrderManager to accept only an array of orders?
It's good that you want to experiment with generics, but this isn't the occasion for it. You say:
The idea ... is to support other items in the future in case I want to expand the app...not just coffee.
But you don't need a generic for that. The only requirement for managing an order is that the order's item be Priceable. Priceable is already a type; you don't need to add a generic type to the mix.
struct Order {
var name: String
var item: Priceable
}
class OrderManager {
private var orders: [Order]
init(orders: [Order]) {
self.orders = orders
}
func add(_ order: Order) {
self.orders.append(order)
}
}
I'm in the process trying to learn and understand generics with associated types in swift.
There is no such thing as "generics with associated types in Swift." There are generics, and there are protocols with associated types (PAT). They have some things in common, but are deeply different concepts used for very different things.
The purpose of a generic is to allow the type to vary over types chosen by the caller.
The purpose of a PAT is to allow a type to be used by existing algorithms, using types chosen by the implementer. Given this, Coffee does not make sense as a protocol. You're trying to treat it like a heterogeneous type. That's not what a PAT is. A PAT is a hook to allow types to be used by algorithms.
class OrderManager<Item> { ... }
This says that OrderManager can hold anything; literally anything at all. It doesn't have to be Priceable. In your case, Item is being coerced into Any, which is definitely not what you wanted (and why Person works when it shouldn't). But it doesn't make a lot of sense that OrderManager is tied to some item type. Do you really want one OrderManager for Coffee and a completely different OrderManager for Espresso? That doesn't match what you're doing at all. OrderManager should work over an Order of anything, right?
It's not really possible to determine what protocols and generics you do need here because you never do anything with OrderManager.orders. Start with the calling code. Start with no generics or protocols. Just let the code duplicate, and then extract that duplication into generics and protocols. If you don't have a clear algorithm (use case) in mind, you should not be creating a protocol yet.
See matt's answer for a starting point, but I'm sure it's not enough for your problem. You likely will need more things (most likely the name of the item for instance). Start with some simple structs (Espresso, BrewedCoffee, etc), and then start working out your calling code, and then you'll probably have more questions we can discuss.
To your question of how to attack this kind of problem, I would begin like this.
First, we have some items for sale. I model them in their most obvious ways:
// An Espresso has no distinguishing characteristics.
struct Espresso {}
// But other coffees have a size.
enum CoffeeSize: String {
case small, medium, large
}
// You must know the size in order to create a coffee. You don't need to know
// its price, or its name, or anything else. But you do have to know its size
// or you can't pour one. So "size" is a property of the type.
struct BrewedCoffee {
let size: CoffeeSize
}
struct Cappuccino {
let size: CoffeeSize
}
Done!
OK, not really done, but seriously, kind of done. We can now make coffee drinks. Until you have some other problem to solve, you really are done. But we do have another problem:
We want to construct an Order, so we can give the customer a bill. An Order is made up of Items. And Items have names and prices. New things can be added to an Order, and I can get textual representation of the whole thing. So we model first what we need:
struct Order {
private (set) var items: [Item]
mutating func add(_ item: Item) {
items.append(item)
}
var totalPrice: Decimal { items.map { $0.price }.reduce(0, +) }
var text: String { items.map { "\($0.name)\t\($0.price)" }.joined(separator: "\n") }
}
And to implement that, we need a protocol that provides name and price:
protocol Item {
var name: String { get }
var price: Decimal { get }
}
Now we'd like an Espresso to be an Item. So we apply retroactive modeling to make it one:
extension Espresso: Item {
var name: String { "Espresso" }
var price: Decimal { 3.00 }
}
And the same thing with BrewedCoffee:
extension BrewedCoffee {
var name: String { "\(size.rawValue.capitalized) Coffee" }
var price: Decimal {
switch size {
case .small: return 1.00
case .medium: return 2.00
case .large: return 3.00
}
}
}
And of course Cappuccino...but you know, as I start to write that I really want to cut-and-paste BrewedCoffee. That suggests maybe there's a protocol hiding in there.
// Just a helper to make syntax prettier.
struct PriceMap {
var small: Decimal
var medium: Decimal
var large: Decimal
}
protocol SizedCoffeeItem: Item {
var size: CoffeeSize { get }
var baseName: String { get }
var priceMap: PriceMap { get }
}
With that, we can implement the requirements of Item:
extension SizedCoffeeItem {
var name: String { "\(size.rawValue.capitalized) \(baseName)" }
var price: Decimal {
switch size {
case .small: return priceMap.small
case .medium: return priceMap.medium
case .large: return priceMap.large
}
}
}
And now the conformances require no code duplication.
extension BrewedCoffee: SizedCoffeeItem {
var baseName: String { "Coffee" }
var priceMap: PriceMap { PriceMap(small: 1.00, medium: 2.00, large: 3.00) }
}
extension Cappuccino: SizedCoffeeItem {
var baseName: String { "Cappuccino" }
var priceMap: PriceMap { PriceMap(small: 2.00, medium: 3.00, large: 4.00) }
}
These two examples are of two different uses of protocols. The first is implementing a heterogeneous collection ([Item]). These kinds of protocols cannot have associated types. The second is to facilitate code sharing between types. These kinds can. But in both cases I didn't add any protocols until I had a clear use case: I needed to be able to add them to Order and get back certain kinds of data. That led us to each step along the way.
As a starting point, model your data simply and design your algorithms. Then adapt your data to the algorithms with protocols. Protocols come late, not early.
You do not need to define Generic type on the class , you should put it on a method like following:
class OrderManager {
func doOrder<T: Priceable, L: Protocol2 >(obj: T) -> L {
// Use obj as a Priceable model
// return a Protocol2 model
}
}
and for send to the class you just send your model for example
varProtocol2 = OrderManager.doOrder(obj: maryOrder.item)
Here is an example with two generic object
protocol prot1 {
var a: Int {get set}
}
protocol protRet {
var b: String {get set}
init()
}
struct prot1Struct: prot1 {
var a: Int
}
struct prot2Struct: protRet {
init() {
b = ""
}
var b: String
}
class Manage {
func Do<T: prot1, L: protRet>(obj: T) -> L {
var ret: L = L()
ret.b = "\(obj.a)"
return ret
}
}
var obj1: prot2Struct?
var paramItem = prot1Struct(a: 10)
obj1 = Manage().Do(obj: paramItem)
Also if you want to use it on a Class you can do it like following:
class manageb<T: prot1, L: protRet> {
func Do(obj: T) -> L {
var ret: L = L()
ret.b = "\(obj.a)"
return ret
}
}
var obj1: prot2Struct?
var paramItem = prot1Struct(a: 10)
let classB = manageb<prot1Struct, prot2Struct>()
obj1 = classB.Do(obj: paramItem)
Is something like
protocol A {
var intCollection: CollectionType<Int> { get }
}
or
protocol A {
typealias T: CollectionType where T.Generator.Element == Int
var intCollection: T
}
possible in Swift 2.1?
Update for Swift 4
Swift 4 now support this feature! read more in here
Not as a nested protocol, but it's fairly straightforward using the type erasers (the "Any" structs).
protocol A {
var intCollection: AnyRandomAccessCollection<Int> { get }
}
This is actually often quite convenient for return values because the caller usually doesn't care so much about the actual type. You just have to throw a return AnyRandomAccessCollection(resultArray) at the end of your function and it all just works. Lots of stdlib now returns Any erasers. For the return value problem, it's almost always the way I recommend. It has the nice side effect of making A concrete, so it's much easier to work with.
If you want to keep the CollectionType, then you need to restrict it at the point that you create a function that needs it. For example:
protocol A {
typealias IntCollection: CollectionType
var intCollection: IntCollection { get }
}
extension A where IntCollection.Generator.Element == Int {
func sum() -> Int {
return intCollection.reduce(0, combine: +)
}
}
This isn't ideal, since it means you can have A with the wrong kind of collection type. They just won't have a sum method. You also will find yourself repeating that "where IntCollection.Generator.Element == Int" in a surprising number of places.
In my experience, it is seldom worth this effort, and you quickly come back to Arrays (which are the dominant CollectionType anyway). But when you need it, these are the two major approaches. That's the best we have today.
You can't do this upright as in your question, and there exists several thread here on SO on the subject of using protocols as type definitions, with content that itself contains Self or associated type requirements (result: this is not allowed). See e.g. the link provided by Christik, or thread Error using associated types and generics.
Now, for you example above, you could do the following workaround, however, perhaps mimicing the behaviour you're looking for
protocol A {
typealias MyCollectionType
typealias MyElementType
func getMyCollection() -> MyCollectionType
func printMyCollectionType()
func largestValue() -> MyElementType?
}
struct B<U: Comparable, T: CollectionType where T.Generator.Element == U>: A {
typealias MyCollectionType = T
typealias MyElementType = U
var myCollection : MyCollectionType
init(coll: MyCollectionType) {
myCollection = coll
}
func getMyCollection() -> MyCollectionType {
return myCollection
}
func printMyCollectionType() {
print(myCollection.dynamicType)
}
func largestValue() -> MyElementType? {
guard var largestSoFar = myCollection.first else {
return nil
}
for item in myCollection {
if item > largestSoFar {
largestSoFar = item
}
}
return largestSoFar
}
}
So you can implement blueprints for your generic collection types in you protocol A, and implement these blueprints in the "interface type" B, which also contain the actual collection as a member property. I have taken the largestValue() method above from here.
Example usage:
/* Examples */
var myArr = B<Int, Array<Int>>(coll: [1, 2, 3])
var mySet = B<Int, Set<Int>>(coll: [10, 20, 30])
var myRange = B<Int, Range<Int>>(coll: 5...10)
var myStrArr = B<String, Array<String>>(coll: ["a", "c", "b"])
myArr.printMyCollectionType() // Array<Int>
mySet.printMyCollectionType() // Set<Int>
myRange.printMyCollectionType() // Range<Int>
myStrArr.printMyCollectionType() // Array<String>
/* generic T type constrained to protocol 'A' */
func printLargestValue<T: A>(coll: T) {
print(coll.largestValue() ?? "Empty collection")
}
printLargestValue(myArr) // 3
printLargestValue(mySet) // 30
printLargestValue(myRange) // 10
printLargestValue(myStrArr) // c
I would like to add an extension to the Set struct, but only if the element of Set is an Array of NSOperations. Is it possible?
I want to write something like this, but it's not a valid code:
extension Set where Element : Array<NSOperation> { }
because type 'Element' constrained to non-protocol type 'Array<NSOperation>. So I wanted to create a protocol and extend Array of NSOperations with this protocol:
protocol ArrayOfOperations { }
extension Array : ArrayOfOperations where Element : NSOperation { }
It doesn't work either because Extension of type 'Array' with constraints cannot have an inheritance clause.
So I'm kinda lost here. Do you have some idea, how to solve this?
Since you cannot make Array<NSOperation> conform to Hashable you'll have to make a small wrapper-struct.
E.g.
struct NSOperationList {
var operations = [NSOperation]()
}
and then build all functionality you need on top of NSOperationList.
So if you want to add support for Set:
extension NSOperationList: Hashable {
var hashValue: Int {
return operations.reduce(0) { $0 ^ $1.hashValue }
}
}
func == (a: NSOperationList, b: NSOperationList) -> Bool {
return a.operations == b.operations
}
import Foundation
let op = NSOperation()
var arr: Array<NSOperation> = []
arr.append(op)
let set = Set(arr)
i don't know what is your trouble, but above snippet compiles without any trouble
I'm trying to define some protocols in a Swift file, however I've noticed that if the protocols have crossed references XCode becomes buggy and it's impossible to work with the project. The example of used protocols might be the one used below:
protocol VIPERPresenterProtocol
{
var view: VIPERViewProtocol? { get set }
var interactor: VIPERInteractorInputProtocol? { get set }
var wireFrame: VIPERWireFrame? { get set }
// /* Add your extra communication methods here */
// /* Presenter -> ViewController */
}
protocol VIPERViewProtocol
{
var presenter: VIPERPresenterProtocol? { get set }
}
Where the VIPERPresenterProtocol has a reference to the VIPERViewProtocol and this last has a reference to the VIPERPresenterProtocol.
This is something that works in Objective-C but that Swift doesn't like. My question is, is this something Apple doesn't expect to support in Swift, if it might be a bug of the Swift language or if I should implement this in any other way.
Your question has a form of:
protocol A
{
var b: B? { get set }
}
protocol B
{
var a: A? { get set }
}
However, while the two protocol declarations compile, any attempt to implement them as such does not:
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
// on their own, the two protocol declerations compile
class Ca: A { // Does not compile: --> Segmentation fault 11
var b: B?
}
This does not happen if we break the cycle:
protocol A {}
protocol B {
var a: A? { get set }
}
class Ca: A {}
class Cb: B {
var a: A?
}
let cb = Cb() // --> {nil}
cb.a = Ca() // --> {{Ca}}
cb.a // --> {Ca}
Or if we define the two protocols in terms of concrete types:
protocol A {
var b: Cb? { get set }
}
protocol B {
var a: Ca? { get set }
}
class Ca: A {
var b: Cb?
let i = "A"
}
class Cb: B {
var a: Ca?
let i = "B"
}
let cb = Cb() // --> {nil "B"}
cb.a = Ca() // --> {{{...}} "B"}
cb.a // --> {{nil "A"}}
cb.a!.b = Cb() // --> {{{...} "A"}}
My impression is that the type checker cannot yet deal with recursive type declarations. Whether it ever will, may be an open question even to Apple at this point, though, because of the clear intention to facilitate functional idioms, this must at least be a possibility.
I have answered a similar question before, though, as I eventually realised with the help of #newacct, not identical.
EDIT
I have just upgraded to Xcode 6.1 GM Seed and things have changed! The following snippet now compiles and appears to run fine!
protocol A {
var b: B? { get set }
}
protocol B {
var a: A? { get set }
}
class Ca: A {
var b: B?
}
class Cb: B {
var a: A?
}
let a = Ca() // --> {nil}
let b = Cb() // --> {nil}
a.b = b // --> {{{...}}}
b.a = a // --> {{{...}}}
(This improvement, however, does not extend to recursively defined associated types.)
I was trying to build something similar too for VIPER, and I encountered the same problems.
I add something to the good answer of milos: I succeeded to break the cycle even when using associated types, using a couple of supporting protocols.
protocol _VIPERViewProtocol {
}
protocol VIPERViewProtocol : _VIPERViewProtocol {
typealias P:_VIPERPresenterProtocol
var presenter: P! {get set}
}
protocol _VIPERPresenterProtocol {
}
protocol VIPERPresenterProtocol : _VIPERPresenterProtocol {
typealias W:_VIPERViewProtocol
var view: W! {get set}
}
This has the advantage of letting the compiler infer the right type of the associated presenter and view, for example:
class BasePresenter : VIPERPresenterProtocol {
var view : BaseView!
}
class BaseView : VIPERViewProtocol {
var presenter: BasePresenter!
}
var p = BasePresenter()
// p.view is correctly recognized as BaseView!
This is valid as long as you use an associated type. Since there is no covariance for properties in Swift, the above code would not compile if you change it like this:
protocol VIPERViewProtocol : _VIPERViewProtocol {
var presenter: _VIPERPresenterProtocol! {get set}
}
Anyway, stepping back to the VIPER architecture, this helps only for giving the concrete classes a template that they must implement.
It would be much more useful if we could define a "builder" method that takes the generic objects conforming to the protocols (wireframe, presenter..), and that wires up all the components.
Unfortunately, something like this doesn't work:
func builder(p:VIPERPresenterProtocol, v:VIPERViewProtocol) {
p.view = v
v.presenter = p
}
compiler complains about Protocol 'VIPERViewProtocol' can only be used as a generic constraint because it has Self or associated type requirements.
Maybe one solution to explore is generics, but I still have to think about it.