DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Why "Polyglot Programming" or "Do It Yourself Programming Languages" or "Language Oriented Programming" sucks?
  • Apache Doris vs Elasticsearch: An In-Depth Comparative Analysis
  • Doris vs Elasticsearch: A Comparison and Practical Cost Case Study
  • Finally, an ORM That Matches Modern Architectural Patterns!

Trending

  • Medallion Architecture: Why You Need It and How To Implement It With ClickHouse
  • Event-Driven Architectures: Designing Scalable and Resilient Cloud Solutions
  • Beyond ChatGPT, AI Reasoning 2.0: Engineering AI Models With Human-Like Reasoning
  • Issue and Present Verifiable Credentials With Spring Boot and Android
  1. DZone
  2. Coding
  3. Languages
  4. Groovy Closures: this, owner, delegate Let's Make a DSL.

Groovy Closures: this, owner, delegate Let's Make a DSL.

By 
Alex Staveley user avatar
Alex Staveley
·
May. 07, 14 · Interview
Likes (11)
Comment
Save
Tweet
Share
66.6K Views

Join the DZone community and get the full member experience.

Join For Free

Groovy closures are super cool. To fully understand them, I think it's really important to understand the meaning of this, owner and delegate. In general:

  • this: refers to the instance of the class that the closure was defined in.
  • owner: is the same as this, unless the closure was defined inside another closure in which case the owner refers to the outer closure.
  • delegate: is the same as owner. But, it is the only one that can be programmatically changed, and it is the one that makes Groovy closures really powerful.
Confused? Let's look at some code.
class MyClass {
  def outerClosure = {
    println this.class.name    // outputs MyClass
    println owner.class.name    // outputs MyClass
    println delegate.class.name  //outputs MyClass
    def nestedClosure = {
      println this.class.name    // outputs MyClass
      println owner.class.name    // outputs MyClass$_closure1
      println delegate.class.name  // outputs MyClass$_closure1
    }
    nestedClosure()
  }
}
 
def closure = new MyClass().closure
closure()

With respect to above code:

  • The this value always refers to the instance of the enclosing class.
  • owner is always the same as this, except for nested closures.
  • delegate is the same as owner by default. It can be changed and we will see that in a sec.

So what is the point of this, owner, delegate? Well remember, that closures are not just anonymous functions. If they were we could just call them Lambdas and we wouldn't have to come up with another word, would we?

Where closures go beyond lambdas is that they bind or "close over" variables that are not explicitly defined in the closure's scope. Again, let's take a look at some code.

class MyClass {
  String myString = "myString1"
  def outerClosure = {
    println myString;     // outputs myString1
    def nestedClosure = {
       println myString;  // outputs myString1
    }
    nestedClosure()
  }
}
 
MyClass myClass = new MyClass()
def closure = new MyClass().outerClosure
closure()
 
println myClass.myString 

Ok, so both the closure and the nestedClosure have access to variables on the instance of the class they were defined in. That's obvious. But, how exactly do they resolve the myString reference? Well it's like this. If the variable was not defined explicitly in the closure, the this scope is then checked, then the owner scope and then the delegatescope. In this example, myString is not defined in either of the closures, so groovy checks their this references and sees the myString is defined there and uses that. Ok, let's take a look at an example where it can't find a variable in the closure and can't find it on the closure's this scope, but it can find's it in the closure's owner scope.

class MyClass {
  def outerClosure = {
    def myString = "outerClosure";     
    def nestedClosure = {
       println myString;  // outputs outerClosure
    }
    nestedClosure()
  }
}
 
MyClass myClass = new MyClass()
def closure = new MyClass().closure
closure()

In this case, Groovy can't find myString in the nestedClosure or in the this scope. It then checks the owner scope, which for the nestedClosure is the outerClosure. It finds myString there and uses that. Now, let's take a look at an example where Groovy can't find a variable in the closure, or on this or the owner scope but can find it in on closure'sdelegate scope. As discussed earlier the owner delegate scope is the same as the owner scope, unless it is explicitly changed. So, to make this a bit more interesting, let's change the delegate.

class MyOtherClass {
  String myString = "I am over in here in myOtherClass"
}
 
class MyClass {
  def closure = {
    println myString
  }
}
 
 
MyClass myClass = new MyClass()
def closure = new MyClass().closure
closure.delegate = new MyOtherClass()
closure()   // outputs: "I am over in here in myOtherClass"

The ability to have so much control over the lexical scope of closures in Groovy gives enormous power. Even when the delegate is set it can be change to something else, this means we can make the behavior of the closure super dynamic.

class MyOtherClass {
  String myString = "I am over in here in myOtherClass"
}
 
class MyOtherClass2 {
  String myString = "I am over in here in myOtherClass2"
}
 
class MyClass {
  def closure = {
    println myString
  }
}
 
 
MyClass myClass = new MyClass()
def closure = new MyClass().closure
closure.delegate = new MyOtherClass()  
closure()     // outputs: I am over in here in myOtherClass
 
closure = new MyClass().closure
closure.delegate = new MyOtherClass2() 
closure()     // outputs: I am over in here in myOtherClass2

Ok, so it should be a bit clearer now what this, owner and delegate actually correspond to. As stated, the closure itself will be checked first, followed by the closure's this scope, than the closure's owner, then its delegate. However, Groovy is so flexible this strategy can be changed. Every closure has a property called resolvedStrategy. This can be set to:

  • Closure.OWNER_FIRST
  • Closure.DELEGATE_FIRST
  • Closure.OWNER_ONLY
  • Closure.DELEGATE_ONLY

So where is a good example of a practical usage of the dynamic setting of the delegate property. Well you see in the GORM for Grails. Suppose we have the following domain class:

class Author {
   String name 
 
   static constraints = {
       name size: 10..15
   }
}

In the Author class we can see a constraint defined using what looks like a DSL whereas in the Java / Hibernate world we would not being able to write an expressive DSL and instead use an annotation (which is better than XML but still not as neat as a DSL). So, how come we can use a DSL in Groovy then? Well it is because of the capabilities delegate setting on closures adds to Groovy's metaprogramming toolbox. In the Author GORM object, constraints is a closure, that invokes a name method with one parameter of name size which has the value of the range between 10 and 15. It could also be written less DSL'y as:

class Author {
   String name 
 
   static constraints = {
       name(size: 10..15)
   }
}

Either way, behind the scenes, Grails looks for a constraints closure and assigns its delegate to a special object that synthesizes the constraints logic. In pseudo code, it would be something like this...

// Set the constraints delegate
 
constraints.delegate = new ConstraintsBuilder();  // delegate is assigned before the closure is executed.
 
class ConstraintsBuilder = {
  //
  // ...
  // In every Groovy object methodMissing() is invoked when a method that does not exist on the object is invoked
  // In this case, there is no name() method so methodMissing will be invoked. 
  // ...
  def methodMissing(String methodName, args) {
      
     // We can get the name variable here from the method name
     // We can get that size is 10..15 from the args
     ...
     // Go and do stuff with hibernate to enforce constraints
  }
}

So there you have it. Closures are very powerful, they can delegate out to objects that can be set dynamically at runtime. That plays an important part in Groovy's meta programming capabilities which mean that Groovy can have some very expressive DSLs.

Domain-Specific Language Groovy (programming language)

Published at DZone with permission of Alex Staveley, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Why "Polyglot Programming" or "Do It Yourself Programming Languages" or "Language Oriented Programming" sucks?
  • Apache Doris vs Elasticsearch: An In-Depth Comparative Analysis
  • Doris vs Elasticsearch: A Comparison and Practical Cost Case Study
  • Finally, an ORM That Matches Modern Architectural Patterns!

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!