Instantiate Swift class from string


(Matthew Davies) #1

I am using the Swift build tool & package manager. I'm trying to figure out
how to instantiate a class from a string. For instance, in PHP I can do:

$instance = new $className

I can (in the iOS & OS X runtimes) use "NSClassFromString", but this is
unavailable in the Swift build tool. How can I (or can I?) get the same
functionality?

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | matthew@daviesgeek.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>


(Harlan Haskins) #2

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

You might want to look into a better way of doing that you’re trying to do.

— Harlan

···

On Dec 10, 2015, at 12:42 AM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I am using the Swift build tool & package manager. I'm trying to figure out how to instantiate a class from a string. For instance, in PHP I can do:

$instance = new $className

I can (in the iOS & OS X runtimes) use "NSClassFromString", but this is unavailable in the Swift build tool. How can I (or can I?) get the same functionality?

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | matthew@daviesgeek.com <mailto:matthew@daviesgeek.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jens Alfke) #3

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

···

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org> wrote:


#4

Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

···

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #5

I don't really like the idea of a factory function, but unfortunately that
might be the only way to do it :frowning: However, due to my specific use case, I
don't think a factory function will work. I'm working on a framework that
will need to both instantiate the class from a string (or class type)
*and* call
methods dynamically on it. Which, I'm not sure I can do in the build tools
that are provided in the open source package. Foundation hasn't been fully
implemented and is missing a lot of the methods that would allow this to
work.

@Jens thanks for that blog post. I'll have to make sure I check back to see
what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

···

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org> > wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < > swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class
must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it.
This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary
http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch
statement that matches class names and returns newly initialized instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Daniel Dunbar) #6

Note that you can define a protocol which will allow your framework to instantiate the type, and to call methods on instances of that type. If you can structure your code in this fashion, it can be very elegant in that it doesn't require factory functions and it is type safe.

For example:

···

--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable: Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately that might be the only way to do it :frowning: However, due to my specific use case, I don't think a factory function will work. I'm working on a framework that will need to both instantiate the class from a string (or class type) and call methods dynamically on it. Which, I'm not sure I can do in the build tools that are provided in the open source package. Foundation hasn't been fully implemented and is missing a lot of the methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to see what his solution is for it.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #7

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an
instance of the class, after instantiating it?

···

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com> wrote:

Note that you can define a protocol which will allow your framework to
instantiate the type, and to call methods on instances of that type. If you
can structure your code in this fashion, it can be very elegant in that it
doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable:
Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately that
might be the only way to do it :frowning: However, due to my specific use case, I
don't think a factory function will work. I'm working on a framework that
will need to both instantiate the class from a string (or class type)
*and* call methods dynamically on it. Which, I'm not sure I can do in the
build tools that are provided in the open source package. Foundation hasn't
been fully implemented and is missing a lot of the methods that would allow
this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to
see what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> > wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users < >> swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < >> swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded
class must conform to.

You might want to look into a better way of doing that you’re trying to
do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it.
This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary
http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch
statement that matches class names and returns newly initialized instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Dan Stenmark) #8

NSSelectorFromString() is still available in Swift, and you should be able to use the result of that in performSelector, though I’m hesitant to support this approach as it flies in the face of the safety Swift tries to enforce. I’m curious about your use case here; are you trying to create some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

···

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com <mailto:daniel_dunbar@apple.com>> wrote:
Note that you can define a protocol which will allow your framework to instantiate the type, and to call methods on instances of that type. If you can structure your code in this fashion, it can be very elegant in that it doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable: Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I don't really like the idea of a factory function, but unfortunately that might be the only way to do it :frowning: However, due to my specific use case, I don't think a factory function will work. I'm working on a framework that will need to both instantiate the class from a string (or class type) and call methods dynamically on it. Which, I'm not sure I can do in the build tools that are provided in the open source package. Foundation hasn't been fully implemented and is missing a lot of the methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to see what his solution is for it.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #9

I'm building a URL router in which I'd like to pass a controller and a
method. I don't want to instantiate all the controllers up front and pass
the methods in as closures, nor do I want old controller instances still
kept around. If there's a better way, I'm definitely open to any
suggestions. I'm still learning the "Swift" way to do things.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

···

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark <daniel.j.stenmark@gmail.com> wrote:

NSSelectorFromString() is still available in Swift, and you should be able
to use the result of that in performSelector, though I’m hesitant to
support this approach as it flies in the face of the safety Swift tries to
enforce. I’m curious about your use case here; are you trying to create
some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an
instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com> > wrote:

Note that you can define a protocol which will allow your framework to
instantiate the type, and to call methods on instances of that type. If you
can structure your code in this fashion, it can be very elegant in that it
doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable:
Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users < >> swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately
that might be the only way to do it :frowning: However, due to my specific use
case, I don't think a factory function will work. I'm working on a
framework that will need to both instantiate the class from a string (or
class type) *and* call methods dynamically on it. Which, I'm not sure I
can do in the build tools that are provided in the open source package.
Foundation hasn't been fully implemented and is missing a lot of the
methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to
see what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> >> wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users < >>> swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < >>> swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded
class must conform to.

You might want to look into a better way of doing that you’re trying to
do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it.
This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary
http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch
statement that matches class names and returns newly initialized instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(David Owens II) #10

You have the protocol conformance, why can’t you simply call the method directly?

···

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a method. I don't want to instantiate all the controllers up front and pass the methods in as closures, nor do I want old controller instances still kept around. If there's a better way, I'm definitely open to any suggestions. I'm still learning the "Swift" way to do things.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark <daniel.j.stenmark@gmail.com <mailto:daniel.j.stenmark@gmail.com>> wrote:
NSSelectorFromString() is still available in Swift, and you should be able to use the result of that in performSelector, though I’m hesitant to support this approach as it flies in the face of the safety Swift tries to enforce. I’m curious about your use case here; are you trying to create some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com <mailto:daniel_dunbar@apple.com>> wrote:
Note that you can define a protocol which will allow your framework to instantiate the type, and to call methods on instances of that type. If you can structure your code in this fashion, it can be very elegant in that it doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable: Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I don't really like the idea of a factory function, but unfortunately that might be the only way to do it :frowning: However, due to my specific use case, I don't think a factory function will work. I'm working on a framework that will need to both instantiate the class from a string (or class type) and call methods dynamically on it. Which, I'm not sure I can do in the build tools that are provided in the open source package. Foundation hasn't been fully implemented and is missing a lot of the methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to see what his solution is for it.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #11

Yes I have the protoco
​l​
, but the problem is that I would want to be able to call a method on the
class that isn't necessarily defined in the protocol.

I.e., I would like to be able to do something like this
​:​

​---​

protocol Controller {
  init()
}

class MainController : Controller {

  required init() {}

  func index() -> String {
    return "This is the index"
  }
}

class Router {
  func get(url: String, ctrl: Controller.Type, method: String) {
    let inst = ctrl.init()
* // Run the method that is passed in here*
  }
}

let router = Router()
router.get("/", ctrl: MainController.self, method: "index")
​---​

Does that make sense as to what I'm trying to accomplish? As I said, I'm
open to suggestions. I'm relatively new to Swift's design patterns, so I
may be thinking about this in completely the wrong way…

···

On Thu, Dec 10, 2015 at 12:48 David Owens II <david@owensd.io> wrote:

You have the protocol conformance, why can’t you simply call the method
directly?

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a
method. I don't want to instantiate all the controllers up front and pass
the methods in as closures, nor do I want old controller instances still
kept around. If there's a better way, I'm definitely open to any
suggestions. I'm still learning the "Swift" way to do things.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark < > daniel.j.stenmark@gmail.com> wrote:

NSSelectorFromString() is still available in Swift, and you should be
able to use the result of that in performSelector, though I’m hesitant to
support this approach as it flies in the face of the safety Swift tries to
enforce. I’m curious about your use case here; are you trying to create
some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users < >> swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on
an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com> >> wrote:

Note that you can define a protocol which will allow your framework to
instantiate the type, and to call methods on instances of that type. If you
can structure your code in this fashion, it can be very elegant in that it
doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable:
Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users < >>> swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately
that might be the only way to do it :frowning: However, due to my specific use
case, I don't think a factory function will work. I'm working on a
framework that will need to both instantiate the class from a string (or
class type) *and* call methods dynamically on it. Which, I'm not sure I
can do in the build tools that are provided in the open source package.
Foundation hasn't been fully implemented and is missing a lot of the
methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to
see what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
  <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> >>> wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users < >>>> swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < >>>> swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded
class must conform to.

You might want to look into a better way of doing that you’re trying to
do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it.
This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary
http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch
statement that matches class names and returns newly initialized instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Brent Royal-Gordon) #12

For URL routing, I would currently suggest generating code at compile time. Someday you might be able to replace this with a macro-based DSL, but for now, I don't see a better option.

On the bright side, this does mean you'll have actual machine code doing your routing, which might be faster than a more dynamic system.

···

Sent from my iPad

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a method. I don't want to instantiate all the controllers up front and pass the methods in as closures, nor do I want old controller instances still kept around. If there's a better way, I'm definitely open to any suggestions. I'm still learning the "Swift" way to do things.

Matthew Davies
Junior Developer, GeoStrategies
Director of Photography, OffBlock Films
209-225-3246 | 209-202-3284 | daviesgeek@gmail.com | daviesgeek.com
     

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark <daniel.j.stenmark@gmail.com> wrote:
NSSelectorFromString() is still available in Swift, and you should be able to use the result of that in performSelector, though I’m hesitant to support this approach as it flies in the face of the safety Swift tries to enforce. I’m curious about your use case here; are you trying to create some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

Matthew Davies
Junior Developer, GeoStrategies
Director of Photography, OffBlock Films
209-225-3246 | 209-202-3284 | daviesgeek@gmail.com | daviesgeek.com
     

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com> wrote:
Note that you can define a protocol which will allow your framework to instantiate the type, and to call methods on instances of that type. If you can structure your code in this fashion, it can be very elegant in that it doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable: Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately that might be the only way to do it :frowning: However, due to my specific use case, I don't think a factory function will work. I'm working on a framework that will need to both instantiate the class from a string (or class type) and call methods dynamically on it. Which, I'm not sure I can do in the build tools that are provided in the open source package. Foundation hasn't been fully implemented and is missing a lot of the methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to see what his solution is for it.

Matthew Davies
Junior Developer, GeoStrategies
Director of Photography, OffBlock Films
209-225-3246 | 209-202-3284 | daviesgeek@gmail.com | daviesgeek.com
     

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> wrote:
Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jens Alfke) #13

Since HTTP only has a handful of standard methods/verbs, you can just define a Swift method for each one in your protocol (get, put, delete, etc.) and use a switch statement on the `method` parameter to dispatch to the right one.

This is a case where you wouldn’t want to use dynamic lookup anyway, since the method name you’d be looking up and calling would be chosen by the remote client. That’s the sort of thing that’s just begging to be exploited (I.e. someone opens a TCP socket and sends “getWithoutCheckingAuth /admin/secretdata.txt HTTP/1.1”…)

—Jens

···

On Dec 10, 2015, at 1:01 PM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

  func get(url: String, ctrl: Controller.Type, method: String) {
    let inst = ctrl.init()
    // Run the method that is passed in here
  }


(Matthew Davies) #14

I could do that, and that would work, but I figured out a way of doing
this.

import Foundation

protocol Controller {
init()
}

class Main : Controller {
required init() {}
func index() -> String {
return "INDEX"
}
}

let inst = Main()
let method = Main.index
method(inst)

func run<T>(ctrl: Controller.Type, method: (T -> () -> String)) {
let inst = ctrl.init()
let handler = method(inst as! T)
print(handler())
}

I've posted the source code for the router here:
https://github.com/daviesgeek/swiftrouter
It's very much incomplete, so keep that in mind when you're looking at it.
The relevant code is here:
https://github.com/daviesgeek/swiftrouter/blob/master/Sources/Router.swift#L19

Thanks so much for everyone's help!

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

···

On Thu, Dec 10, 2015 at 3:25 PM, Jens Alfke <jens@mooseyard.com> wrote:

On Dec 10, 2015, at 1:01 PM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

  func get(url: String, ctrl: Controller.Type, method: String) {
    let inst = ctrl.init()
* // Run the method that is passed in here*
  }

Since HTTP only has a handful of standard methods/verbs, you can just
define a Swift method for each one in your protocol (get, put, delete,
etc.) and use a switch statement on the `method` parameter to dispatch to
the right one.

This is a case where you wouldn’t want to use dynamic lookup anyway, since
the method name you’d be looking up and calling would be chosen by the
remote client. That’s the sort of thing that’s just begging to be exploited
(I.e. someone opens a TCP socket and sends “getWithoutCheckingAuth
/admin/secretdata.txt HTTP/1.1”…)

—Jens


(Daniel Dunbar) #15

Yes I have the protoco​l​, but the problem is that I would want to be able to call a method on the class that isn't necessarily defined in the protocol.

You should only call methods that are defined in the protocol, and you should extend the protocol as necessary. You can always have instances conform to additional protocols and use conditional casts, if necessary.

The value of this approach is that it is statically type safe, and users of your framework can easily tell what methods they need to implement to work with it.

- Daniel

···

On Dec 10, 2015, at 1:01 PM, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I.e., I would like to be able to do something like this​:​

​---​

protocol Controller {
  init()
}

class MainController : Controller {

  required init() {}

  func index() -> String {
    return "This is the index"
  }
}

class Router {
  func get(url: String, ctrl: Controller.Type, method: String) {
    let inst = ctrl.init()
    // Run the method that is passed in here
  }
}

let router = Router()
router.get("/", ctrl: MainController.self, method: "index")
​---​

Does that make sense as to what I'm trying to accomplish? As I said, I'm open to suggestions. I'm relatively new to Swift's design patterns, so I may be thinking about this in completely the wrong way…

On Thu, Dec 10, 2015 at 12:48 David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:
You have the protocol conformance, why can’t you simply call the method directly?

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I'm building a URL router in which I'd like to pass a controller and a method. I don't want to instantiate all the controllers up front and pass the methods in as closures, nor do I want old controller instances still kept around. If there's a better way, I'm definitely open to any suggestions. I'm still learning the "Swift" way to do things.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark <daniel.j.stenmark@gmail.com <mailto:daniel.j.stenmark@gmail.com>> wrote:
NSSelectorFromString() is still available in Swift, and you should be able to use the result of that in performSelector, though I’m hesitant to support this approach as it flies in the face of the safety Swift tries to enforce. I’m curious about your use case here; are you trying to create some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com <mailto:daniel_dunbar@apple.com>> wrote:
Note that you can define a protocol which will allow your framework to instantiate the type, and to call methods on instances of that type. If you can structure your code in this fashion, it can be very elegant in that it doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable: Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I don't really like the idea of a factory function, but unfortunately that might be the only way to do it :frowning: However, due to my specific use case, I don't think a factory function will work. I'm working on a framework that will need to both instantiate the class from a string (or class type) and call methods dynamically on it. Which, I'm not sure I can do in the build tools that are provided in the open source package. Foundation hasn't been fully implemented and is missing a lot of the methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to see what his solution is for it.

Matthew Davies
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <tel:209-225.3246> | 209-202-3284 <tel:209-202-3284> | daviesgeek@gmail.com <mailto:daviesgeek@gmail.com> | daviesgeek.com <https://daviesgeek.com/>
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Please no factory madness in Swift. This stuff is bad enough in Java - don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

IIRC this isn’t possible because there’s no Runtime to query for classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded class must conform to.

You might want to look into a better way of doing that you’re trying to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it. This kind of dynamism is often the best tool for the job, and a lot of Cocoa developers are frustrated by its absence in Swift. For example, there’s a series of blog posts from earlier this year by the highly respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently at Omni]:
  http://inessential.com/swiftdiary
  http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch statement that matches class names and returns newly initialized instances.

—Jens

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #16

You're right. I should be using a class instead…

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

···

On Thu, Dec 10, 2015 at 3:47 PM, Daniel Dunbar <daniel_dunbar@apple.com> wrote:

On Dec 10, 2015, at 1:01 PM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

Yes I have the protoco
​l​
, but the problem is that I would want to be able to call a method on the
class that isn't necessarily defined in the protocol.

You should only call methods that are defined in the protocol, and you
should extend the protocol as necessary. You can always have instances
conform to additional protocols and use conditional casts, if necessary.

The value of this approach is that it is statically type safe, and users
of your framework can easily tell what methods they need to implement to
work with it.

- Daniel

I.e., I would like to be able to do something like this
​:​

​---​

protocol Controller {
  init()
}

class MainController : Controller {

  required init() {}

  func index() -> String {
    return "This is the index"
  }
}

class Router {
  func get(url: String, ctrl: Controller.Type, method: String) {
    let inst = ctrl.init()
* // Run the method that is passed in here*
  }
}

let router = Router()
router.get("/", ctrl: MainController.self, method: "index")
​---​

Does that make sense as to what I'm trying to accomplish? As I said, I'm
open to suggestions. I'm relatively new to Swift's design patterns, so I
may be thinking about this in completely the wrong way…

On Thu, Dec 10, 2015 at 12:48 David Owens II <david@owensd.io> wrote:

You have the protocol conformance, why can’t you simply call the method
directly?

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users < >> swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a
method. I don't want to instantiate all the controllers up front and pass
the methods in as closures, nor do I want old controller instances still
kept around. If there's a better way, I'm definitely open to any
suggestions. I'm still learning the "Swift" way to do things.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark < >> daniel.j.stenmark@gmail.com> wrote:

NSSelectorFromString() is still available in Swift, and you should be
able to use the result of that in performSelector, though I’m hesitant to
support this approach as it flies in the face of the safety Swift tries to
enforce. I’m curious about your use case here; are you trying to create
some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users < >>> swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on
an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
  <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com >>> > wrote:

Note that you can define a protocol which will allow your framework to
instantiate the type, and to call methods on instances of that type. If you
can structure your code in this fashion, it can be very elegant in that it
doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable:
Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users < >>>> swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately
that might be the only way to do it :frowning: However, due to my specific use
case, I don't think a factory function will work. I'm working on a
framework that will need to both instantiate the class from a string (or
class type) *and* call methods dynamically on it. Which, I'm not sure
I can do in the build tools that are provided in the open source package.
Foundation hasn't been fully implemented and is missing a lot of the
methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to
see what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek>
<http://us.linkedin.com/in/daviesgeek> <http://twitter.com/daviesgeek>
  <http://daviesgeek.com/feed.xml> <http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> >>>> wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users < >>>>> swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < >>>>> swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded
class must conform to.

You might want to look into a better way of doing that you’re trying
to do.

I disagree with “a better way” — “a workaround” is how I’d rephrase
it. This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary

http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a
switch statement that matches class names and returns newly initialized
instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________

swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Matthew Davies) #17

Can you clarify a bit on that? So, what you're saying is to generate
routing code based off the DSL router I've written?

···

On Thu, Dec 10, 2015 at 13:52 Brent Royal-Gordon <brent@architechies.com> wrote:

For URL routing, I would currently suggest generating code at compile
time. Someday you might be able to replace this with a macro-based DSL, but
for now, I don't see a better option.

On the bright side, this does mean you'll have actual machine code doing
your routing, which might be faster than a more dynamic system.

Sent from my iPad

On Dec 10, 2015, at 12:22 PM, Matthew Davies via swift-users < > swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a
method. I don't want to instantiate all the controllers up front and pass
the methods in as closures, nor do I want old controller instances still
kept around. If there's a better way, I'm definitely open to any
suggestions. I'm still learning the "Swift" way to do things.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:47 AM, Dan Stenmark < > daniel.j.stenmark@gmail.com> wrote:

NSSelectorFromString() is still available in Swift, and you should be
able to use the result of that in performSelector, though I’m hesitant to
support this approach as it flies in the face of the safety Swift tries to
enforce. I’m curious about your use case here; are you trying to create
some kind of dynamic proxy for a remote object ala NSXPCConnection?

Dan

On Dec 10, 2015, at 10:33 AM, Matthew Davies via swift-users < >> swift-users@swift.org> wrote:

Ooh okay. I think that should work for my purposes. Thanks.

Somewhat related to this, how would I then call a method dynamically on
an instance of the class, after instantiating it?

---
class Graph {
  func call(method: String) {
    // Something goes here
  }

  func redraw() -> String {
    return "Redraws"
  }
}

let inst = Graph()
inst.call("redraw")
---

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 10:18 AM, Daniel Dunbar <daniel_dunbar@apple.com> >> wrote:

Note that you can define a protocol which will allow your framework to
instantiate the type, and to call methods on instances of that type. If you
can structure your code in this fashion, it can be very elegant in that it
doesn't require factory functions and it is type safe.

For example:
--
struct GraphableDescription { }

protocol Graphable {
    /// Construct a graphable item from a description.
    init(description: GraphableDescription)

    func graph()
}

// Example framework method.
func graphItem(description: GraphableDescription, graphable:
Graphable.Type) {
    // Instantiate the graphable.
    let item = graphable.init(description: description)

    // Graph it.
    item.graph()
}

// Example Graphable client.
struct Circle: Graphable {
    init(description: GraphableDescription) { }

    func graph() { }
}

// Example framework client.
func foo() {
    graphItem(GraphableDescription(), graphable: Circle.self)
}
--

- Daniel

On Dec 10, 2015, at 9:59 AM, Matthew Davies via swift-users < >>> swift-users@swift.org> wrote:

I don't really like the idea of a factory function, but unfortunately
that might be the only way to do it :frowning: However, due to my specific use
case, I don't think a factory function will work. I'm working on a
framework that will need to both instantiate the class from a string (or
class type) *and* call methods dynamically on it. Which, I'm not sure I
can do in the build tools that are provided in the open source package.
Foundation hasn't been fully implemented and is missing a lot of the
methods that would allow this to work.

@Jens thanks for that blog post. I'll have to make sure I check back to
see what his solution is for it.

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com/>
Director of Photography, OffBlock Films <http://offblockfilms.com/>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
  <http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

On Thu, Dec 10, 2015 at 9:30 AM, Jan Neumüller <swift-users@swift.org> >>> wrote:

Please no factory madness in Swift. This stuff is bad enough in Java -
don’t infect Swift with it.

Jan

On 10.12.2015, at 18:23, Jens Alfke via swift-users < >>>> swift-users@swift.org> wrote:

On Dec 10, 2015, at 7:26 AM, Harlan Haskins via swift-users < >>>> swift-users@swift.org> wrote:

IIRC this isn’t possible because there’s no Runtime to query for
classnames (it’s inherently unsafe anyway).

It’s not unsafe if you specify a base class/protocol that the loaded
class must conform to.

You might want to look into a better way of doing that you’re trying to
do.

I disagree with “a better way” — “a workaround” is how I’d rephrase it.
This kind of dynamism is often the best tool for the job, and a lot of
Cocoa developers are frustrated by its absence in Swift. For example,
there’s a series of blog posts from earlier this year by the highly
respected Brent Simmons [NetNewsWire, MarsEdit, Glassboard, etc., currently
at Omni]:
http://inessential.com/swiftdiary
http://inessential.com/2015/07/20/swift_diary_1_class_or_struct_from_str

The workaround I’d suggest is a factory function that contains a switch
statement that matches class names and returns newly initialized instances.

—Jens
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jeremy Pereira) #18

The way I would do this is to define my controller interface with a protocol and then have a dictionary of the following type:

  [String: (Request) throws -> Controller]

where Controller is the protocol and Request is the HTTP request.

So you have a dictionary of URLs to functions (or closures) that create instances that conform to the Controller protocol. The closure takes a parameter of the HTTP request so it has the option of choosing the returned instance based on the method or headers or parameters in the request.

In my implementation, I took the path part of the URL and if it was in the dictionary it would use the returned closure to create the controller. If it wasn’t there, I chopped off the last path part and tried again and so on until I was left with “/“ which always maps to a controller.

The closure is allowed to throw so I could put something like this in for a path

    { _ in throw HTTPError(404) }

which would be handled further up the call chain by generating a 404 response.

···

On 10 Dec 2015, at 20:22, Matthew Davies via swift-users <swift-users@swift.org> wrote:

I'm building a URL router in which I'd like to pass a controller and a method. I don't want to instantiate all the controllers up front and pass the methods in as closures, nor do I want old controller instances still kept around. If there's a better way, I'm definitely open to any suggestions. I'm still learning the "Swift" way to do things.


(Brent Royal-Gordon) #19

(Sorry for the repeat, Matthew.)

Can you clarify a bit on that? So, what you're saying is to generate routing code based off the DSL router I've written?

Yes, unless you can modify your DSL so you can directly provide your controller classes, you’ll probably need to generate code.

By “provide your controller classes”, I mean that you could make a routes file which looked something like this (this routing syntax is loosely inspired by Rails):

  import MyFramework.Router
  
  // UsersController.self is an instance which represents the UsersController class.
  // It’s of type UsersController.Type, which might (for instance) be a subtype of WebController.Type, etc.
  Router.root.resources(UsersController.self, path: “users”) { users in
    users.resources(PostsController.self, path: “posts”) { posts in
      // PostsController.comments is a way to retrieve a closure which calls PostsController’s comments() instance method.
      // You use it by saying something like `myClosure(myControllerInstance)(arg1, arg2, etc)`.
      posts.get(PostsController.comments, path: “comments”)
    }
    users.resources(CommentsController.self, path: “comments”)
  }

Note that in all cases you pass instances, not names, to your routing APIs. This allows you to write code that can work with any compatible class or method without any danger of trying to use a class or method that doesn’t exist.

But using this approach limits the flexibility of your routing DSL’s design. For instance, you can’t just take the string “users” and infer that you should use UsersController. If you want that sort of more sophisticated behavior, you’re going to need to generate Swift code instead.

···

--
Brent Royal-Gordon
Architechies


(Matthew Davies) #20

Okay I'll have to dig more into using that sort of syntax.

And no problem :wink:

*Matthew Davies*
Junior Developer, GeoStrategies <http://geostrategies.com>
Director of Photography, OffBlock Films <http://offblockfilms.com>
209-225-3246 <209-225.3246> | 209-202-3284 | daviesgeek@gmail.com |
daviesgeek.com
<http://facebook.com/daviesgeek> <http://us.linkedin.com/in/daviesgeek>
<http://twitter.com/daviesgeek> <http://daviesgeek.com/feed.xml>
<http://github.com/daviesgeek>

···

On Thu, Dec 10, 2015 at 4:12 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

(Sorry for the repeat, Matthew.)

> Can you clarify a bit on that? So, what you're saying is to generate
routing code based off the DSL router I've written?

Yes, unless you can modify your DSL so you can directly provide your
controller classes, you’ll probably need to generate code.

By “provide your controller classes”, I mean that you could make a routes
file which looked something like this (this routing syntax is loosely
inspired by Rails):

        import MyFramework.Router

        // UsersController.self is an instance which represents the
UsersController class.
        // It’s of type UsersController.Type, which might (for instance)
be a subtype of WebController.Type, etc.
        Router.root.resources(UsersController.self, path: “users”) { users
in
                users.resources(PostsController.self, path: “posts”) {
posts in
                        // PostsController.comments is a way to retrieve a
closure which calls PostsController’s comments() instance method.
                        // You use it by saying something like
`myClosure(myControllerInstance)(arg1, arg2, etc)`.
                        posts.get(PostsController.comments, path:
“comments”)
                }
                users.resources(CommentsController.self, path: “comments”)
        }

Note that in all cases you pass instances, not names, to your routing
APIs. This allows you to write code that can work with any compatible class
or method without any danger of trying to use a class or method that
doesn’t exist.

But using this approach limits the flexibility of your routing DSL’s
design. For instance, you can’t just take the string “users” and infer that
you should use UsersController. If you want that sort of more sophisticated
behavior, you’re going to need to generate Swift code instead.

--
Brent Royal-Gordon
Architechies